You've already forked go-semantic-release
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)
136 lines
3.7 KiB
Go
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
|
|
}
|