mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-23 18:35:06 +00:00
BREAKING CHANGE: `JiraIssueId` has been renamed to `JiraIssueID`. This impacts the value for `pattern_maps` in `config.yml`. * chore(ci): add golangci-lint action * chore(lint): address errcheck lint failures * chore(lint): address misspell lint failures * chore(lint): address gocritic lint failures * chore(lint): address golint lint failures * chore(lint): address structcheck lint failures * chore(lint): address gosimple lint failures * chore(lint): address gofmt lint failures * chore(ci): port to official golangci-lint github action * Update golangci configuration for better coverage Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * fix: file is not goimports-ed Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * fix: golint and exported functions comments Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * chore(lint): address gosec G304 warning * chore(lint): address uparam warnings * chore(lint): address scopelint lint failures * fix: cyclomatic complexity Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * chore(lint): address prealloc warning, noting that we are warning for now * chore(lint): address govet and errorlint failures * chore: clean up defer logic when checking errors Co-authored-by: Khosrow Moossavi <khos2ow@gmail.com>
218 lines
4.7 KiB
Go
218 lines
4.7 KiB
Go
package chglog
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type commitExtractor struct {
|
|
opts *Options
|
|
}
|
|
|
|
func newCommitExtractor(opts *Options) *commitExtractor {
|
|
return &commitExtractor{
|
|
opts: opts,
|
|
}
|
|
}
|
|
|
|
func (e *commitExtractor) Extract(commits []*Commit) ([]*CommitGroup, []*Commit, []*Commit, []*NoteGroup) {
|
|
commitGroups := []*CommitGroup{}
|
|
noteGroups := []*NoteGroup{}
|
|
mergeCommits := []*Commit{}
|
|
revertCommits := []*Commit{}
|
|
|
|
filteredCommits := commitFilter(commits, e.opts.CommitFilters, e.opts.NoCaseSensitive)
|
|
|
|
for _, commit := range commits {
|
|
if commit.Merge != nil {
|
|
mergeCommits = append(mergeCommits, commit)
|
|
continue
|
|
}
|
|
|
|
if commit.Revert != nil {
|
|
revertCommits = append(revertCommits, commit)
|
|
continue
|
|
}
|
|
}
|
|
|
|
for _, commit := range filteredCommits {
|
|
if commit.Merge == nil && commit.Revert == nil {
|
|
e.processCommitGroups(&commitGroups, commit, e.opts.NoCaseSensitive)
|
|
}
|
|
|
|
e.processNoteGroups(¬eGroups, commit)
|
|
}
|
|
|
|
e.sortCommitGroups(commitGroups)
|
|
e.sortNoteGroups(noteGroups)
|
|
|
|
return commitGroups, mergeCommits, revertCommits, noteGroups
|
|
}
|
|
|
|
func (e *commitExtractor) processCommitGroups(groups *[]*CommitGroup, commit *Commit, noCaseSensitive bool) {
|
|
var group *CommitGroup
|
|
|
|
// commit group
|
|
raw, ttl := e.commitGroupTitle(commit)
|
|
|
|
for _, g := range *groups {
|
|
rawTitleTmp := g.RawTitle
|
|
if noCaseSensitive {
|
|
rawTitleTmp = strings.ToLower(g.RawTitle)
|
|
}
|
|
|
|
rawTmp := raw
|
|
if noCaseSensitive {
|
|
rawTmp = strings.ToLower(raw)
|
|
}
|
|
if rawTitleTmp == rawTmp {
|
|
group = g
|
|
}
|
|
}
|
|
|
|
if group != nil {
|
|
group.Commits = append(group.Commits, commit)
|
|
} else if raw != "" {
|
|
*groups = append(*groups, &CommitGroup{
|
|
RawTitle: raw,
|
|
Title: ttl,
|
|
Commits: []*Commit{commit},
|
|
})
|
|
}
|
|
}
|
|
|
|
func (e *commitExtractor) processNoteGroups(groups *[]*NoteGroup, commit *Commit) {
|
|
if len(commit.Notes) != 0 {
|
|
for _, note := range commit.Notes {
|
|
e.appendNoteToNoteGroups(groups, note)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e *commitExtractor) appendNoteToNoteGroups(groups *[]*NoteGroup, note *Note) {
|
|
exist := false
|
|
|
|
for _, g := range *groups {
|
|
if g.Title == note.Title {
|
|
exist = true
|
|
g.Notes = append(g.Notes, note)
|
|
}
|
|
}
|
|
|
|
if !exist {
|
|
*groups = append(*groups, &NoteGroup{
|
|
Title: note.Title,
|
|
Notes: []*Note{note},
|
|
})
|
|
}
|
|
}
|
|
|
|
func (e *commitExtractor) commitGroupTitle(commit *Commit) (string, string) {
|
|
var (
|
|
raw string
|
|
ttl string
|
|
)
|
|
|
|
if title, ok := dotGet(commit, e.opts.CommitGroupBy); ok {
|
|
if v, ok := title.(string); ok {
|
|
raw = v
|
|
if t, ok := e.opts.CommitGroupTitleMaps[v]; ok {
|
|
ttl = t
|
|
} else {
|
|
ttl = strings.Title(raw)
|
|
}
|
|
}
|
|
}
|
|
|
|
return raw, ttl
|
|
}
|
|
|
|
func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) { //nolint:gocyclo
|
|
// NOTE(khos2ow): this function is over our cyclomatic complexity goal.
|
|
// Be wary when adding branches, and look for functionality that could
|
|
// be reasonably moved into an injected dependency.
|
|
|
|
order := make(map[string]int)
|
|
if e.opts.CommitGroupSortBy == "Custom" {
|
|
for i, t := range e.opts.CommitGroupTitleOrder {
|
|
order[t] = i
|
|
}
|
|
}
|
|
|
|
// groups
|
|
// TODO(khos2ow): move the inline sort function to
|
|
// conceret implementation of sort.Interface in order
|
|
// to reduce cyclomatic complaxity.
|
|
sort.Slice(groups, func(i, j int) bool {
|
|
if e.opts.CommitGroupSortBy == "Custom" {
|
|
return order[groups[i].RawTitle] < order[groups[j].RawTitle]
|
|
}
|
|
|
|
var (
|
|
a, b interface{}
|
|
ok bool
|
|
)
|
|
|
|
a, ok = dotGet(groups[i], e.opts.CommitGroupSortBy)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
b, ok = dotGet(groups[j], e.opts.CommitGroupSortBy)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
res, err := compare(a, "<", b)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return res
|
|
})
|
|
|
|
// commits
|
|
for _, group := range groups {
|
|
group := group // pin group to avoid potential bugs with passing group to lower functions
|
|
|
|
// TODO(khos2ow): move the inline sort function to
|
|
// conceret implementation of sort.Interface in order
|
|
// to reduce cyclomatic complaxity.
|
|
sort.Slice(group.Commits, func(i, j int) bool {
|
|
var (
|
|
a, b interface{}
|
|
ok bool
|
|
)
|
|
|
|
a, ok = dotGet(group.Commits[i], e.opts.CommitSortBy)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
b, ok = dotGet(group.Commits[j], e.opts.CommitSortBy)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
res, err := compare(a, "<", b)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return res
|
|
})
|
|
}
|
|
}
|
|
|
|
func (e *commitExtractor) sortNoteGroups(groups []*NoteGroup) {
|
|
// groups
|
|
sort.Slice(groups, func(i, j int) bool {
|
|
return strings.ToLower(groups[i].Title) < strings.ToLower(groups[j].Title)
|
|
})
|
|
|
|
// notes
|
|
for _, group := range groups {
|
|
group := group // pin group to avoid potential bugs with passing group to lower functions
|
|
sort.Slice(group.Notes, func(i, j int) bool {
|
|
return strings.ToLower(group.Notes[i].Title) < strings.ToLower(group.Notes[j].Title)
|
|
})
|
|
}
|
|
}
|