Files
go-semantic-release/internal/analyzer/analyzer.go
maulik13 dc4d1c581a feat(analyzer): update AnalyzedCommit to add flexibility in parsing a message
This provides flexibility of parsing and rendering structured messages
with more detail in the changelog and helps extract metadata from the 
message. The new structure can be used to split a message in multiple 
blocks (e.g. footer)
2021-02-23 14:25:09 +01:00

136 lines
3.7 KiB
Go

// Package analyzer provides different commit analyzer
package analyzer
import (
"fmt"
"regexp"
"strings"
"github.com/Nightapes/go-semantic-release/internal/shared"
"github.com/Nightapes/go-semantic-release/pkg/config"
log "github.com/sirupsen/logrus"
)
// Analyzer struct
type Analyzer struct {
analyzeCommits analyzeCommits
ChangelogConfig config.ChangelogConfig
AnalyzerConfig config.AnalyzerConfig
}
// Rule for commits
type Rule struct {
Tag string
TagString string
Release shared.Release
Changelog bool
}
type analyzeCommits interface {
analyze(commit shared.Commit, tag Rule) *shared.AnalyzedCommit
getRules() []Rule
}
// New Analyzer struct for given commit format
func New(format string, analyzerConfig config.AnalyzerConfig, chglogConfig config.ChangelogConfig) (*Analyzer, error) {
analyzer := &Analyzer{
AnalyzerConfig: analyzerConfig,
ChangelogConfig: chglogConfig,
}
switch format {
case ANGULAR:
analyzer.analyzeCommits = newAngular()
log.Debugf("Commit format set to %s", ANGULAR)
case CONVENTIONAL:
analyzer.analyzeCommits = newConventional(analyzerConfig)
log.Debugf("Commit format set to %s", CONVENTIONAL)
default:
return nil, fmt.Errorf("invalid commit format: %s", format)
}
return analyzer, nil
}
// GetRules from current mode
func (a *Analyzer) GetRules() []Rule {
return a.analyzeCommits.getRules()
}
// Analyze commits and return commits split by major,minor,patch
func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.AnalyzedCommit {
analyzedCommits := make(map[shared.Release][]shared.AnalyzedCommit)
analyzedCommits["major"] = make([]shared.AnalyzedCommit, 0)
analyzedCommits["minor"] = make([]shared.AnalyzedCommit, 0)
analyzedCommits["patch"] = make([]shared.AnalyzedCommit, 0)
analyzedCommits["none"] = make([]shared.AnalyzedCommit, 0)
for _, commit := range commits {
for _, rule := range a.analyzeCommits.getRules() {
analyzedCommit := a.analyzeCommits.analyze(commit, rule)
if analyzedCommit == nil {
continue
}
if a.ChangelogConfig.PrintAll || rule.Changelog {
analyzedCommit.Print = true
}
if analyzedCommit.IsBreaking {
analyzedCommits["major"] = append(analyzedCommits["major"], *analyzedCommit)
break
}
analyzedCommits[rule.Release] = append(analyzedCommits[rule.Release], *analyzedCommit)
break
}
}
log.Debugf("Analyzed commits: major=%d minor=%d patch=%d none=%d", len(analyzedCommits["major"]), len(analyzedCommits["minor"]), len(analyzedCommits["patch"]), len(analyzedCommits["none"]))
return analyzedCommits
}
func getMessageParts(msg string) (header string, bodyBlocks []string){
firstSplit := strings.SplitN(msg, "\n", 2)
header = firstSplit[0]
bodyBlocks = make([]string, 0)
if len(firstSplit) < 2 {
return
}
// Trim and then split by a blank line
remaining := strings.Trim(firstSplit[1], "\n")
bodyBlocks = strings.Split(remaining, "\n\n")
return
}
func parseMessageBlock(msg string, prefixes []string) shared.MessageBlock {
for _, prefix := range prefixes {
if !strings.HasPrefix(msg, prefix + ":") {
continue
}
content := strings.Replace(msg, prefix+":", "", 1)
return shared.MessageBlock{
Label: prefix,
Content: strings.TrimSpace(content),
}
}
return shared.MessageBlock{
Label: "",
Content: msg,
}
}
//
// getRegexMatchedMap will match a regex with named groups and map the matching
// results to corresponding group names
//
func getRegexMatchedMap(regEx, url string) (paramsMap map[string]string) {
var compRegEx = regexp.MustCompile(regEx)
match := compRegEx.FindStringSubmatch(url)
paramsMap = make(map[string]string)
for i, name := range compRegEx.SubexpNames() {
if i > 0 && i <= len(match) {
paramsMap[name] = match[i]
}
}
return paramsMap
}