-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsection.go
110 lines (89 loc) · 2.77 KB
/
section.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package gitlabcodeowners
import (
"errors"
"fmt"
"strconv"
"strings"
)
const (
maxSquareBracketsInHeader = 2
partCountWithApprovalAndOwners = 3
partCountWithApprovalOrOwners = 2
)
var (
errNoMatchingBracketCount = errors.New("no matching bracket count")
errTooMuchBracketsFound = errors.New("too much brackets found")
)
type section struct {
name string
approvals int
owners []string
rules []rule
}
func parseSectionHeader(header string) (section, error) {
err := checkBracketCountInSectionHeader(header)
if err != nil {
return section{}, fmt.Errorf("failed to parse section header '%s': %w", header, err)
}
// remove optional indicator from header
optional := strings.HasPrefix(header, "^")
if optional {
header = header[1:]
}
name, approvals, owners := extractPartsFromSectionHeader(header)
return section{
name: strings.TrimSpace(name),
approvals: parseApprovalCount(approvals, optional),
owners: strings.Fields(owners),
rules: []rule{},
}, nil
}
func checkBracketCountInSectionHeader(header string) error {
count := strings.Count(header, "[")
switch {
case count != strings.Count(header, "]"):
return errNoMatchingBracketCount
case count > maxSquareBracketsInHeader:
return errTooMuchBracketsFound
case count == 0:
// This should never happen because the line is only
// parsed as a header if it starts with `^[` or `[`.
panic("No square brackets found in section header, this should not happen")
}
return nil
}
func extractPartsFromSectionHeader(header string) (name, approvals, owners string) { //nolint:nonamedreturns,lll // give the return param strings a name
// split header into parts based on square brackets
parts := strings.FieldsFunc(header, func(c rune) bool {
return c == ']' || c == '['
})
switch {
// approval count and default owners
case len(parts) == partCountWithApprovalAndOwners:
return parts[0], parts[1], parts[2]
// only approval count but no default owners
case len(parts) == partCountWithApprovalOrOwners && strings.Count(header, "[") == 2:
return parts[0], parts[1], ""
// default owners but no approval count
case len(parts) == partCountWithApprovalOrOwners:
return parts[0], "", parts[1]
// only section name
case len(parts) == 1:
return parts[0], "", ""
}
// This should never happen because amount of square brackets
// is checked before this function gets called.
panic("Invalid amount of square brackets in section header, this should not happen")
}
func parseApprovalCount(count string, optional bool) int {
if optional {
return 0
}
approvals, err := strconv.Atoi(strings.TrimSpace(count))
// fallback to default approval count if parsing failed
// or if zero or a negative value is provided
if err != nil || approvals < 1 {
return 1
}
return approvals
}