Skip to content

Commit

Permalink
fix: correclty parse valid commits
Browse files Browse the repository at this point in the history
  • Loading branch information
SKalt committed Oct 19, 2020
1 parent dafe0a3 commit 9ff453c
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 44 deletions.
10 changes: 6 additions & 4 deletions pkg/parser/combinators.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,19 +259,21 @@ func Delimeted(start Parser, middle Parser, end Parser) Parser {
}
func Many0(parser Parser) Parser {
return func(input []rune) (*Result, error) {
i := 0
window := make([]rune, len(input))
copy(window, input)
results := []Result{}
for { // the highest possible # of times callable
result, err := parser(input[i:])
for range input { // the highest possible # of times callable
result, err := parser(window)
if err != nil {
break
}
results = append(results, *result)
window = result.Remaining
if len(result.Remaining) == 0 {
break
}
}
return &Result{Children: results, Remaining: input[i:]}, nil
return &Result{Children: results, Remaining: window}, nil
}
}

Expand Down
49 changes: 26 additions & 23 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,32 +66,33 @@ func ParseHead(head []rune) (*CCHeader, error) {
if ctxErr != nil {
return &header, ctxErr
}
switch true {
case len(ctx.Children) > 0:
header.Type = ctx.Children[0].Value
case len(ctx.Children) > 1:
header.Scope = ctx.Children[1].Value
case len(ctx.Children) > 2:
header.BreakingChange = ctx.Children[2].Type == "BreakingChangeBang"
for _, child := range ctx.Children {
switch child.Type {
case "BreakingChangeBang":
header.BreakingChange = true
case "Scope":
header.Scope = child.Value
case "CommitType":
header.Type = child.Value
}
}
//
desc, descErr := Sequence(ColonSep, TakeUntil(Empty))(ctx.Remaining)
if descErr == nil {
header.Description = desc.Children[1].Value
}
return &header, descErr
}

var BreakingChange = Tag("BREAKING CHANGE: ")
var BreakingChange = Tag("BREAKING CHANGE")

var KebabWord = Regex(`[\w-]+`)
var FooterPrefix = Any(
BreakingChange,
var FooterToken = Any(
Marked("BreakingChange")(Sequence(BreakingChange, ColonSep)),
Sequence(KebabWord, Any(ColonSep, Tag(" #"))),
)

var Body = Sequence(Newline, TakeUntil(Any(Empty, FooterPrefix)))
var Footer = Sequence(FooterPrefix, TakeUntil(Any(Empty, FooterPrefix)))
var Body = Sequence(Newline, TakeUntil(Any(Empty, FooterToken)))
var Footer = Sequence(FooterToken, TakeUntil(Any(Empty, FooterToken)))
var Footers = Many0(Footer)

func ParseRest(input []rune) (*CCRest, error) {
Expand All @@ -107,12 +108,12 @@ func ParseRest(input []rune) (*CCRest, error) {
}
footers := make([]string, len(result.Children))
breakingChange := false
for i := range result.Children {
child := result.Children[i]
if child.Type == "BreakingChange" {
for i, footer := range result.Children {
token := footer.Children[0]
if token.Type == "BreakingChange" {
breakingChange = true
}
footers[i] = child.Value
footers[i] = footer.Value
}
rest.BreakingChange = breakingChange
rest.Footers = footers
Expand Down Expand Up @@ -146,12 +147,14 @@ func ParseCC(fullCommit string) (*CC, error) {
cc.Scope = header.Scope
cc.BreakingChange = header.BreakingChange
otherLines = strings.TrimRight(otherLines, "\n\r\t ")
rest, restErr := ParseRest([]rune(otherLines))
if restErr != nil {
panic(restErr)
if len(otherLines) > 0 {
rest, restErr := ParseRest([]rune(otherLines))
if restErr != nil {
panic(restErr)
}
cc.Body = rest.Body
cc.Footers = rest.Footers
cc.BreakingChange = cc.BreakingChange || rest.BreakingChange
}
cc.Body = rest.Body
cc.Footers = rest.Footers
cc.BreakingChange = cc.BreakingChange || rest.BreakingChange
return cc, nil
}
99 changes: 82 additions & 17 deletions pkg/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var validCCwithBothBreakingChangeBangAndFooter = `refactor!: drop support for No
BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.
`
var validCCWithOnlyDescription = `docs: correct spelling of CHANGELOG`
var validCCWithOnlyHeader = `docs: correct spelling of CHANGELOG`
var validCCWithScope = `feat(lang): add polish language`
var validCCWithFooters = `fix: correct minor typos in code
Expand Down Expand Up @@ -144,41 +144,106 @@ func TestParsingFullCommit(t *testing.T) {
t.FailNow()
}
if actual.Type != expected.Type {
fmt.Printf("expected: %+v actual: %+v", expected.Type, actual.Type)
fmt.Printf("Type: expected: %+v actual: %+v\n", expected.Type, actual.Type)
t.FailNow()
}
if actual.Scope != expected.Scope {
fmt.Printf("expected: %+v actual: %+v", expected.Type, actual.Type)
fmt.Printf("Scope: expected: %+v actual: %+v\n", expected.Type, actual.Type)
t.FailNow()
}
if actual.BreakingChange != expected.BreakingChange {
fmt.Printf("expected: %+v actual: %+v", expected.BreakingChange, actual.BreakingChange)
fmt.Printf("BreakingChange: expected: %+v actual: %+v\n", expected.BreakingChange, actual.BreakingChange)
t.FailNow()
}
if actual.Body != expected.Body {
fmt.Printf("expected: %+v actual: %+v", expected.Body, actual.Body)
fmt.Printf("Body: expected: `%+v`\nactual: `%+v`\n", expected.Body, actual.Body)
t.FailNow()
}
if len(actual.Footers) != len(expected.Footers) {
fmt.Printf("expected: %+v actual: %+v", expected.Footers, actual.Footers)
fmt.Printf("Footers: expected: %+v actual: %+v\n", expected.Footers, actual.Footers)
t.FailNow()
}
for i := range actual.Footers {
if actual.Footers[i] != expected.Footers[i] {
fmt.Printf("expected: '%+v' actual: '%+v'", expected.Footers[i], actual.Footers[i])
fmt.Printf("expected: '%+v' actual: '%+v'\n", expected.Footers[i], actual.Footers[i])
t.FailNow()
}
}
}
}
t.Run("can parse a valid cc with a breaking change footer",
test(validCCwithBreakingChangeFooter, CC{
Type: "feat",
Scope: "",
Description: "allow provided config object to extend other configs",
Body: "",
Footers: []string{
"BREAKING CHANGE: `extends` key in config file is now used for extending other config files",
},
}))
prefix := "can parse a valid cc with "
t.Run(prefix+"breaking change footer", test(validCCwithBreakingChangeFooter, CC{
Type: "feat",
Scope: "",
Description: "allow provided config object to extend other configs",
Body: "",
BreakingChange: true,
Footers: []string{
"BREAKING CHANGE: `extends` key in config file is now used for extending other config files",
},
}))
t.Run(prefix+"a bang", test(validCCWithBreakingChangeBang, CC{
Type: "refactor",
Scope: "",
Description: "drop support for node 6",
Body: "",
BreakingChange: true,
}))
t.Run(prefix+"both a bang and a breaking change footer", test(validCCwithBothBreakingChangeBangAndFooter, CC{
Type: "refactor",
Scope: "",
Description: "drop support for Node 6",
BreakingChange: true,
Body: "",
Footers: []string{
"BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.",
},
}))
t.Run(prefix+"only a header", test(validCCWithOnlyHeader, CC{
Type: "docs",
Scope: "",
Description: "correct spelling of CHANGELOG",
Body: "",
Footers: []string{},
BreakingChange: false,
}))
t.Run(prefix+"no body or footers but a scope", test(validCCWithScope, CC{
Type: "feat",
Scope: "lang",
Description: "add polish language",
Body: "",
Footers: []string{},
BreakingChange: false,
}))
t.Run(prefix+"footers", test(validCCWithFooters, CC{
Type: "fix",
Scope: "",
Description: "correct minor typos in code",
Body: `see the issue for details
on typos fixed.
`,
Footers: []string{
"Reviewed-by: Z\n",
"Refs #133"},
BreakingChange: false,
}))
t.Run(prefix+"reversion", test(validCCreversion, CC{
Type: "revert",
Scope: "",
Description: "let us never again speak of the noodle incident",
Body: "",
Footers: []string{"Refs: 676104e, a215868"},
BreakingChange: false,
}))
// // template:
// t.Run(prefix+"", test(,CC{
// Type: "",
// Scope: "",
// Description: "",
// Body: "",
// Footers: []string{},
// BreakingChange: false,
// }))
}

0 comments on commit 9ff453c

Please # to comment.