wip: horrible hack for parsing commit footers

This commit is contained in:
2020-10-31 20:43:46 +00:00
parent 5d205a639c
commit 12ad99911a
3 changed files with 201 additions and 4 deletions

View File

@@ -12,6 +12,7 @@ type Commit struct {
}
type Footer struct {
Name string
Body string
Name string
Body string
Reference bool
}

View File

@@ -12,8 +12,16 @@ const (
crlf = "\r\n"
)
var rHeader = regexp.MustCompile(
`^([\w\-]*)(?:\(([\w\$\.\/\-\* ]*)\))?(!)?\: (.*)$`,
var (
rHeader = regexp.MustCompile(
`^([\w\-]*)(?:\(([\w\$\.\/\-\* ]*)\))?(!)?\: (.*)$`,
)
rFooterToken = regexp.MustCompile(
`^([\w-]+|BREAKING CHANGE):\s\s*(.*)$`,
)
rFooterTicket = regexp.MustCompile(
`^([\w-]+)\s+(#\S.*)$`,
)
)
func parseHeader(header []byte) (*Commit, error) {
@@ -34,6 +42,61 @@ func parseHeader(header []byte) (*Commit, error) {
}, nil
}
func footers(paragraph []byte) []*Footer {
footers := []*Footer{}
lines := bytes.Split(paragraph, []byte{lf})
if !rFooterToken.Match(lines[0]) && !rFooterTicket.Match(lines[0]) {
return footers
}
var cName string
var cBody []byte
var cRef bool
for _, line := range lines {
if m := rFooterToken.FindSubmatch(line); m != nil {
if cName != "" {
footers = append(footers, &Footer{
Name: cName,
Body: string(bytes.TrimSpace(cBody)),
Reference: cRef,
})
cName = ""
cRef = false
}
cName = string(m[1])
cBody = m[2]
cRef = false
} else if m := rFooterTicket.FindSubmatch(line); m != nil {
if cName != "" {
footers = append(footers, &Footer{
Name: cName,
Body: string(bytes.TrimSpace(cBody)),
Reference: cRef,
})
cName = ""
cRef = false
}
cName = string(m[1])
cBody = m[2]
cRef = true
} else {
cBody = append(cBody, []byte{lf}...)
cBody = append(cBody, line...)
}
}
if cName != "" {
footers = append(footers, &Footer{
Name: cName,
Body: string(bytes.TrimSpace(cBody)),
Reference: cRef,
})
}
return footers
}
func paragraphs(commitMsg []byte) [][]byte {
paras := bytes.Split(
bytes.TrimSpace(normlizeLinefeeds(commitMsg)),

View File

@@ -175,6 +175,139 @@ func Test_parseHeader(t *testing.T) {
}
}
func Test_footers(t *testing.T) {
type args struct {
paragraph []byte
}
tests := []struct {
name string
args args
want []*Footer
}{
{
name: "without footer",
args: args{[]byte("this is not a fooder")},
want: []*Footer{},
},
{
name: "token footer on second line",
args: args{[]byte("this is not a fooder\nDone-By: John")},
want: []*Footer{},
},
{
name: "ticket footer on second line",
args: args{[]byte("this is not a fooder\nFixes #42")},
want: []*Footer{},
},
{
name: "breaking change footer on second line",
args: args{[]byte("this is not a fooder\nBREAKING CHANGE: Oops")},
want: []*Footer{},
},
{
name: "token footer",
args: args{[]byte("Reviewed-By: John Smith")},
want: []*Footer{{Name: "Reviewed-By", Body: "John Smith"}},
},
{
name: "breaking change footer",
args: args{[]byte("BREAKING CHANGE: Oopsy")},
want: []*Footer{{Name: "BREAKING CHANGE", Body: "Oopsy"}},
},
{
name: "ticket footer",
args: args{[]byte("Fixes #82")},
want: []*Footer{{Name: "Fixes", Body: "#82", Reference: true}},
},
{
name: "multiple token footers",
args: args{[]byte(
"Reviewed-By: John\n" +
"Committer: Smith\n",
)},
want: []*Footer{
{Name: "Reviewed-By", Body: "John"},
{Name: "Committer", Body: "Smith"},
},
},
{
name: "multiple ticket footers",
args: args{[]byte("Fixes #82\nFixes #74")},
want: []*Footer{
{Name: "Fixes", Body: "#82", Reference: true},
{Name: "Fixes", Body: "#74", Reference: true},
},
},
{
name: "multiple breaking change footers",
args: args{[]byte(
"BREAKING CHANGE: Oopsy\n" +
"BREAKING CHANGE: Again!",
)},
want: []*Footer{
{Name: "BREAKING CHANGE", Body: "Oopsy"},
{Name: "BREAKING CHANGE", Body: "Again!"},
},
},
{
name: "mixture of footer types",
args: args{[]byte(
"Fixes #930\n" +
"BREAKING CHANGE: Careful!\n" +
"Reviewed-By: Maria\n",
)},
want: []*Footer{
{Name: "Fixes", Body: "#930", Reference: true},
{Name: "BREAKING CHANGE", Body: "Careful!"},
{Name: "Reviewed-By", Body: "Maria"},
},
},
{
name: "multi-line footers",
args: args{[]byte(
"Description: Lorem ipsum dolor sit amet, consectetur\n" +
"adipiscing elit.Praesent eleifend lorem non purus\n" +
"finibus, interdum hendrerit sem bibendum.\n" +
"Fixes #94\n" +
"Misc-Other: Etiam porttitor mollis nulla, egestas\n" +
"facilisis nisi molestie ut. Quisque mi mi, commodo\n" +
"ut mattis a, scelerisque eu elit.\n" +
"BREAKING CHANGE: Duis id nulla eget velit maximus\n" +
"varius et egestas sem. Ut mi risus, pretium quis\n" +
"cursus quis, porttitor in ipsum.\n",
)},
want: []*Footer{
{
Name: "Description",
Body: "Lorem ipsum dolor sit amet, consectetur\n" +
"adipiscing elit.Praesent eleifend lorem non purus\n" +
"finibus, interdum hendrerit sem bibendum.",
},
{Name: "Fixes", Body: "#94", Reference: true},
{
Name: "Misc-Other",
Body: "Etiam porttitor mollis nulla, egestas\n" +
"facilisis nisi molestie ut. Quisque mi mi, commodo\n" +
"ut mattis a, scelerisque eu elit.",
},
{
Name: "BREAKING CHANGE",
Body: "Duis id nulla eget velit maximus\n" +
"varius et egestas sem. Ut mi risus, pretium quis\n" +
"cursus quis, porttitor in ipsum.",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := footers(tt.args.paragraph)
assert.Equal(t, tt.want, got)
})
}
}
func Test_paragraph(t *testing.T) {
type args struct {
input []byte