Skip to content

Commit 2231d1f

Browse files
🌱 cron: make CSV header optional (3/n) (#2261)
* Make CSV header optional. Signed-off-by: Spencer Schrock <sschrock@google.com> * Appease linter. Signed-off-by: Spencer Schrock <sschrock@google.com> * Address PR feedback. Signed-off-by: Spencer Schrock <sschrock@google.com> Signed-off-by: Spencer Schrock <sschrock@google.com>
1 parent bde0ae1 commit 2231d1f

File tree

5 files changed

+70
-4
lines changed

5 files changed

+70
-4
lines changed

cron/internal/data/iterator.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121
"io"
22+
"reflect"
2223

2324
"github.com/jszwec/csvutil"
2425

@@ -36,21 +37,45 @@ type Iterator interface {
3637
func MakeIteratorFrom(reader io.Reader) (Iterator, error) {
3738
csvReader := csv.NewReader(reader)
3839
csvReader.Comment = '#'
39-
dec, err := csvutil.NewDecoder(csvReader)
40+
header, err := csvutil.Header(RepoFormat{}, "csv")
41+
if err != nil {
42+
return nil, fmt.Errorf("error in csvutil.Header: %w", err)
43+
}
44+
dec, err := csvutil.NewDecoder(csvReader, header...)
4045
if err != nil {
4146
return nil, fmt.Errorf("error in csvutil.NewDecoder: %w", err)
4247
}
4348
return &csvIterator{decoder: dec}, nil
4449
}
4550

4651
type csvIterator struct {
47-
decoder *csvutil.Decoder
48-
err error
49-
next RepoFormat
52+
decoder *csvutil.Decoder
53+
err error
54+
next RepoFormat
55+
afterHeader bool
56+
}
57+
58+
// returns true on the first call if the most recently decoded record is a header.
59+
// always returns false on subsequent calls, as this is only intended to evaluate the first line.
60+
func (reader *csvIterator) isHeader() bool {
61+
if reader.afterHeader {
62+
return false
63+
}
64+
header, err := csvutil.Header(RepoFormat{}, "csv")
65+
if err != nil {
66+
reader.err = err
67+
return false
68+
}
69+
lastRead := reader.decoder.Record()
70+
reader.afterHeader = true
71+
return reflect.DeepEqual(header, lastRead)
5072
}
5173

5274
func (reader *csvIterator) HasNext() bool {
5375
reader.err = reader.decoder.Decode(&reader.next)
76+
if reader.isHeader() {
77+
reader.err = reader.decoder.Decode(&reader.next)
78+
}
5479
return !errors.Is(reader.err, io.EOF)
5580
}
5681

cron/internal/data/iterator_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,42 @@ func TestCsvIterator(t *testing.T) {
153153
},
154154
},
155155
},
156+
{
157+
name: "Ignore First Header Row",
158+
filename: "testdata/ignore_header.csv",
159+
outcomes: []outcome{
160+
{
161+
hasError: false,
162+
repo: RepoFormat{
163+
Repo: "github.com/owner1/repo1",
164+
},
165+
},
166+
{
167+
// will error due to GitHub URL sanity check
168+
hasError: true,
169+
repo: RepoFormat{
170+
Repo: "repo",
171+
},
172+
},
173+
},
174+
},
175+
{
176+
name: "No Header Row",
177+
filename: "testdata/no_header.csv",
178+
outcomes: []outcome{
179+
{
180+
hasError: false,
181+
repo: RepoFormat{
182+
Repo: "github.com/owner1/repo1",
183+
},
184+
},
185+
},
186+
},
187+
{
188+
name: "Only Header Row",
189+
filename: "testdata/only_header.csv",
190+
outcomes: []outcome{},
191+
},
156192
}
157193

158194
for _, testcase := range testcases {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
repo,metadata
2+
github.com/owner1/repo1,
3+
repo,metadata
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github.com/owner1/repo1,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
repo,metadata

0 commit comments

Comments
 (0)