Skip to content

Commit e740c32

Browse files
committed
Implement JSON exporter
1 parent af18812 commit e740c32

File tree

8 files changed

+130
-11
lines changed

8 files changed

+130
-11
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ Here is an example of how to create an on-call duty plan
1818
}
1919
EOL
2020

21-
./ocs create --start "2024-01-01 00:00:00" --end "2024-03-29 00:00:00" --team-file demo.json --output table
21+
./ocsctl create \
22+
--start "2024-01-01 00:00:00" \
23+
--end "2024-03-29 00:00:00" \
24+
--team-file demo.json \
25+
--output table
2226
```
2327

2428
## Contributing

cmd/create_command.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,21 @@ type Converter int
2424
const (
2525
CVS Converter = iota
2626
Table
27+
JSON
2728
)
2829

2930
func RunCreateShiftPlan(arguments []string) error {
30-
enums := map[string]Converter{"CVS": CVS, "Table": Table}
31+
enums := map[string]Converter{"CVS": CVS, "Table": Table, "json": JSON}
3132
converters := map[Converter]func() apis.Exporter{
3233
Table: func() apis.Exporter {
3334
return export.NewTableExporter()
3435
},
3536
CVS: func() apis.Exporter {
3637
return export.NewCVSCExporter()
3738
},
39+
JSON: func() apis.Exporter {
40+
return export.NewJSONExporter()
41+
},
3842
}
3943

4044
str := new(time.Time)
@@ -50,7 +54,7 @@ func RunCreateShiftPlan(arguments []string) error {
5054
createCommand.Func("start", "(required) start time of the schedule plan", cli.TimeValueVar(str))
5155
createCommand.Func("end", "(required) end time of the schedule plan", cli.TimeValueVar(end))
5256
createCommand.Func("team-file", "(required) path to the file that contain all on-call duties", cli.FilePathVar(teamFilePath))
53-
createCommand.Func("output", "output format. One of (cvs, table)", cli.EnumValueVar(enums, &transform))
57+
createCommand.Func("output", "output format. One of (cvs, table, json)", cli.EnumValueVar(enums, &transform))
5458
createCommand.Usage = func() {
5559
fmt.Fprintf(os.Stdout, "Create on-call schedule\n")
5660
fmt.Fprintf(os.Stdout, "\nUsage\n")

internal/export/cv.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"github.com/orltom/on-call-schedule/pkg/apis"
99
)
1010

11+
var _ apis.Exporter = &CVSExporter{}
12+
1113
type CVSExporter struct{}
1214

1315
func (c *CVSExporter) Write(shifts []apis.Shift, writer io.Writer) error {

internal/export/json.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package export
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
8+
"github.com/orltom/on-call-schedule/pkg/apis"
9+
)
10+
11+
var _ apis.Exporter = &JSONExporter{}
12+
13+
type JSONExporter struct{}
14+
15+
func (c *JSONExporter) Write(plan []apis.Shift, writer io.Writer) error {
16+
if plan == nil {
17+
return fmt.Errorf("plan must not be nil")
18+
}
19+
20+
content, err := json.Marshal(plan)
21+
if err != nil {
22+
return fmt.Errorf("could not marshal plan: %w", err)
23+
}
24+
25+
_, err = writer.Write(content)
26+
if err != nil {
27+
return fmt.Errorf("could not write plan: %w", err)
28+
}
29+
30+
return nil
31+
}
32+
33+
func NewJSONExporter() *JSONExporter {
34+
return &JSONExporter{}
35+
}

internal/export/json_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package export
2+
3+
import (
4+
"github.com/orltom/on-call-schedule/pkg/apis"
5+
"strings"
6+
"testing"
7+
)
8+
9+
func TestJSONExporter_Write(t *testing.T) {
10+
type args struct {
11+
plan []apis.Shift
12+
}
13+
tests := []struct {
14+
name string
15+
args args
16+
wantWriter string
17+
wantErr bool
18+
}{
19+
{
20+
name: "Should create valid CSV",
21+
args: args{
22+
plan: []apis.Shift{
23+
{
24+
Start: date("2024-12-25"),
25+
End: date("2024-12-26"),
26+
Primary: "a",
27+
Secondary: "b",
28+
},
29+
{
30+
Start: date("2024-12-26"),
31+
End: date("2024-12-27"),
32+
Primary: "c",
33+
Secondary: "d",
34+
},
35+
},
36+
},
37+
wantWriter: `[{"start":"2024-12-25T00:00:00Z","end":"2024-12-26T00:00:00Z","primary":"a","secondary":"b"},{"start":"2024-12-26T00:00:00Z","end":"2024-12-27T00:00:00Z","primary":"c","secondary":"d"}]`,
38+
wantErr: false,
39+
},
40+
{
41+
name: "When plan is empty, throw an error",
42+
args: args{
43+
plan: []apis.Shift{},
44+
},
45+
wantWriter: "[]",
46+
wantErr: false,
47+
},
48+
{
49+
name: "When plan is nil, do nothing",
50+
args: args{
51+
plan: nil,
52+
},
53+
wantWriter: "",
54+
wantErr: true,
55+
},
56+
}
57+
for _, tt := range tests {
58+
t.Run(tt.name, func(t *testing.T) {
59+
e := NewJSONExporter()
60+
writer := &strings.Builder{}
61+
err := e.Write(tt.args.plan, writer)
62+
if (err != nil) != tt.wantErr {
63+
t.Errorf("Write() error = %v, wantErr %v", err, tt.wantErr)
64+
}
65+
if content := writer.String(); content != tt.wantWriter {
66+
t.Errorf("Write() json = %v, want = %v", content, tt.wantWriter)
67+
}
68+
})
69+
}
70+
}

internal/export/table.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ func NewTableExporter() *TableExporter {
3131
}
3232

3333
func (e *TableExporter) Write(plan []apis.Shift, writer io.Writer) error {
34+
if plan == nil {
35+
return fmt.Errorf("shifts must not be nil")
36+
}
37+
3438
if err := e.template.Execute(writer, plan); err != nil {
3539
return fmt.Errorf("can not generate CVS: %w", err)
3640
}

internal/export/table_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ func TestTableExporter_Write(t *testing.T) {
5252
wantErr: false,
5353
},
5454
{
55-
name: "When plan is nil, print table header",
55+
name: "When plan is nil, throw an error",
5656
args: args{
5757
plan: nil,
5858
},
59-
wantWriter: "From | To | Primary | Secondary\n----------------------------------------------------------\n\n",
60-
wantErr: false,
59+
wantWriter: "",
60+
wantErr: true,
6161
},
6262
}
6363
for _, tt := range tests {

pkg/apis/plan_types.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import (
66
)
77

88
type Shift struct {
9-
Start time.Time
10-
End time.Time
11-
Primary EmployeeID
12-
Secondary EmployeeID
9+
Start time.Time `json:"start"`
10+
End time.Time `json:"end"`
11+
Primary EmployeeID `json:"primary"`
12+
Secondary EmployeeID `json:"secondary"`
1313
}
1414

1515
type Rule interface {
1616
Match(primary Employee, shifts []Shift, start time.Time, end time.Time) bool
1717
}
1818

1919
type Exporter interface {
20-
Write(shifts []Shift, writer io.Writer) error
20+
Write(plan []Shift, writer io.Writer) error
2121
}

0 commit comments

Comments
 (0)