fix: Fix parsing of revert and body

This commit is contained in:
tsuyoshiwada 2018-02-17 01:40:27 +09:00
parent 153727ed1a
commit 8869631aad
8 changed files with 160 additions and 30 deletions

View file

@ -70,7 +70,7 @@ func TestGeneratorWithTypeScopeSubject(t *testing.T) {
gen := NewGenerator(&Config{
Bin: "git",
WorkingDir: filepath.Join(testRepoRoot, testName),
Template: filepath.Join("fixtures", testName+".md"),
Template: filepath.Join("testdata", testName+".md"),
Info: &Info{
Title: "CHANGELOG Example",
RepositoryURL: "https://github.com/git-chglog/git-chglog",

View file

@ -73,9 +73,7 @@ func TestCommitExtractor(t *testing.T) {
Header: "Revert1",
Notes: []*Note{},
Revert: &Revert{
Raw: "revert1",
Subject: "REVERT1",
Hash: "1",
Header: "REVERT1",
},
},
}

View file

@ -38,6 +38,14 @@ var (
}, delimiter)
)
func joinAndQuoteMeta(list []string, sep string) string {
arr := make([]string, len(list))
for i, s := range list {
arr[i] = regexp.QuoteMeta(s)
}
return strings.Join(arr, sep)
}
type commitParser struct {
client gitcmd.Client
config *Config
@ -53,9 +61,9 @@ type commitParser struct {
func newCommitParser(client gitcmd.Client, config *Config) *commitParser {
opts := config.Options
joinedRefActions := strings.Join(opts.RefActions, "|")
joinedIssuePrefix := strings.Join(opts.IssuePrefix, "|")
joinedNoteKeywords := strings.Join(opts.NoteKeywords, "|")
joinedRefActions := joinAndQuoteMeta(opts.RefActions, "|")
joinedIssuePrefix := joinAndQuoteMeta(opts.IssuePrefix, "|")
joinedNoteKeywords := joinAndQuoteMeta(opts.NoteKeywords, "|")
return &commitParser{
client: client,
@ -65,7 +73,7 @@ func newCommitParser(client gitcmd.Client, config *Config) *commitParser {
reRevert: regexp.MustCompile(opts.RevertPattern),
reRef: regexp.MustCompile("(?i)(" + joinedRefActions + ")\\s?([\\w/\\.\\-]+)?(?:" + joinedIssuePrefix + ")(\\d+)"),
reIssue: regexp.MustCompile("(?:" + joinedIssuePrefix + ")(\\d+)"),
reNotes: regexp.MustCompile("^(?i)[\\s|*]*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
reNotes: regexp.MustCompile("^(?i)\\s*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
reMention: regexp.MustCompile("@([\\w-]+)"),
}
}
@ -76,8 +84,6 @@ func (p *commitParser) Parse(rev string) ([]*Commit, error) {
rev,
"--no-decorate",
"--pretty="+logFormat,
"-n",
"10",
)
if err != nil {
@ -203,25 +209,32 @@ func (p *commitParser) processHeader(commit *Commit, input string) {
}
func (p *commitParser) processBody(commit *Commit, input string) {
input = convNewline(input, "\n")
// body
commit.Body = input
// notes & refs & mentions
commit.Notes = []*Note{}
inNote := false
fenceDetector := newMdFenceDetector()
lines := strings.Split(input, "\n")
for _, line := range lines {
refs := p.parseRefs(line)
if len(refs) > 0 {
inNote = false
commit.Refs = append(commit.Refs, refs...)
}
fenceDetector.Update(line)
mentions := p.parseMentions(line)
if len(mentions) > 0 {
inNote = false
commit.Mentions = append(commit.Mentions, mentions...)
if !fenceDetector.InCodeblock() {
refs := p.parseRefs(line)
if len(refs) > 0 {
inNote = false
commit.Refs = append(commit.Refs, refs...)
}
mentions := p.parseMentions(line)
if len(mentions) > 0 {
inNote = false
commit.Mentions = append(commit.Mentions, mentions...)
}
}
res := p.reNotes.FindAllStringSubmatch(line, -1)
@ -240,6 +253,10 @@ func (p *commitParser) processBody(commit *Commit, input string) {
}
}
p.trimSpaceInNotes(commit)
}
func (*commitParser) trimSpaceInNotes(commit *Commit) {
for _, note := range commit.Notes {
note.Body = strings.TrimSpace(note.Body)
}
@ -326,3 +343,42 @@ func (p *commitParser) uniqMentions(mentions []string) []string {
return arr
}
var (
fenceTypes = []string{
"```",
"~~~",
" ",
"\t",
}
)
type mdFenceDetector struct {
fence int
}
func newMdFenceDetector() *mdFenceDetector {
return &mdFenceDetector{
fence: -1,
}
}
func (d *mdFenceDetector) InCodeblock() bool {
return d.fence > -1
}
func (d *mdFenceDetector) Update(input string) {
for i, s := range fenceTypes {
if d.fence < 0 {
if strings.Index(input, s) == 0 {
d.fence = i
break
}
} else {
if strings.Index(input, s) == 0 && i == d.fence {
d.fence = -1
break
}
}
}
}

View file

@ -2,6 +2,7 @@ package chglog
import (
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"testing"
@ -20,7 +21,7 @@ func TestCommitParserParse(t *testing.T) {
return "", errors.New("")
}
bytes, _ := ioutil.ReadFile(filepath.Join("fixtures", "gitlog.txt"))
bytes, _ := ioutil.ReadFile(filepath.Join("testdata", "gitlog.txt"))
return string(bytes), nil
},
@ -62,10 +63,9 @@ func TestCommitParserParse(t *testing.T) {
"Ref",
"Source",
},
RevertPattern: "^Revert\\s\"([\\s\\S]*)\"\\s*This reverts commit (\\w*)\\.",
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
RevertPatternMaps: []string{
"Subject",
"Hash",
"Header",
},
NoteKeywords: []string{
"BREAKING CHANGE",
@ -230,10 +230,23 @@ BREAKING CHANGE: This is breaking point message.`,
Notes: []*Note{
&Note{
Title: "BREAKING CHANGE",
Body: `This is multiline breaking change note.
Body: fmt.Sprintf(`This is multiline breaking change note.
It is treated as the body of the Note until a mention or reference appears.
We also allow blank lines :)`,
We also allow blank lines :)
Example:
%sjavascript
import { Controller } from 'hoge-fuga';
@autobind
class MyController extends Controller {
constructor() {
super();
}
}
%s`, "```", "```"),
},
},
Mentions: []string{},
@ -241,7 +254,7 @@ We also allow blank lines :)`,
Type: "fix",
Scope: "model",
Subject: "Remove hoge attributes",
Body: `This mixed body message.
Body: fmt.Sprintf(`This mixed body message.
BREAKING CHANGE:
This is multiline breaking change note.
@ -249,8 +262,49 @@ It is treated as the body of the Note until a mention or reference appears.
We also allow blank lines :)
Example:
%sjavascript
import { Controller } from 'hoge-fuga';
@autobind
class MyController extends Controller {
constructor() {
super();
}
}
%s
Fixes #123
Closes username/repository#456`,
Closes username/repository#456`, "```", "```"),
},
&Commit{
Hash: &Hash{
Long: "123456789735dcc4810dda3312b0792236c97c4e",
Short: "12345678",
},
Author: &Author{
Name: "tsuyoshi wada",
Email: "mail@example.com",
Date: time.Unix(int64(1517488587), 0),
},
Committer: &Committer{
Name: "tsuyoshi wada",
Email: "mail@example.com",
Date: time.Unix(int64(1517488587), 0),
},
Merge: nil,
Revert: &Revert{
Header: "fix(core): commit message",
},
Refs: []*Ref{},
Notes: []*Note{},
Mentions: []string{},
Header: "Revert \"fix(core): commit message\"",
Type: "",
Scope: "",
Subject: "",
Body: "This reverts commit f755db78dcdf461dc42e709b3ab728ceba353d1d.",
},
}, commits)
}

View file

@ -30,9 +30,7 @@ type Merge struct {
// Revert ...
type Revert struct {
Raw string
Subject string
Hash string
Header string
}
// Ref ...
@ -96,6 +94,7 @@ type Tag struct {
type Version struct {
Tag *Tag
CommitGroups []*CommitGroup
Commits []*Commit
MergeCommits []*Commit
RevertCommits []*Commit
NoteGroups []*NoteGroup

View file

@ -20,5 +20,20 @@ It is treated as the body of the Note until a mention or reference appears.
We also allow blank lines :)
Example:
```javascript
import { Controller } from 'hoge-fuga';
@autobind
class MyController extends Controller {
constructor() {
super();
}
}
```
Fixes #123
Closes username/repository#456
@@__CHGLOG__@@HASH:123456789735dcc4810dda3312b0792236c97c4e 12345678@@__CHGLOG_DELIMITER__@@AUTHOR:tsuyoshi wada mail@example.com 1517488587@@__CHGLOG_DELIMITER__@@COMMITTER:tsuyoshi wada mail@example.com 1517488587@@__CHGLOG_DELIMITER__@@SUBJECT:Revert "fix(core): commit message"@@__CHGLOG_DELIMITER__@@BODY:This reverts commit f755db78dcdf461dc42e709b3ab728ceba353d1d.

View file

@ -104,3 +104,11 @@ func compareTime(a time.Time, operator string, b time.Time) bool {
return false
}
}
func convNewline(str, nlcode string) string {
return strings.NewReplacer(
"\r\n", nlcode,
"\r", nlcode,
"\n", nlcode,
).Replace(str)
}