From 7208daed1f698cbf3a9e8e4804ff79ee16483089 Mon Sep 17 00:00:00 2001 From: maulik13 Date: Mon, 22 Feb 2021 12:02:39 +0100 Subject: [PATCH] feat(angular): update angular to include new structured fields --- internal/analyzer/analyzer.go | 69 ++++++++++++++++++++++++------- internal/analyzer/angular.go | 46 ++++++++++++++------- internal/analyzer/angular_test.go | 21 ++++++++++ internal/analyzer/conventional.go | 51 +---------------------- 4 files changed, 107 insertions(+), 80 deletions(-) diff --git a/internal/analyzer/analyzer.go b/internal/analyzer/analyzer.go index cb3a797..c9ea762 100644 --- a/internal/analyzer/analyzer.go +++ b/internal/analyzer/analyzer.go @@ -2,6 +2,7 @@ package analyzer import ( + "bufio" "fmt" "regexp" "strings" @@ -90,21 +91,6 @@ func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared. 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 -} - // // getRegexMatchedMap will match a regex with named groups and map the matching // results to corresponding group names @@ -162,3 +148,56 @@ func findFooterToken(text string, separators []string) (token string, sep string } return "", "" } + +// +// getDefaultMessageBlockMap parses a text block and splits in to different sections. +// default logic to distinguish different parts is: +// - Body starts right after the header (without beginning with a token) +// - Body ends when a footer is discovered or text ends +// - A footer is detected when it starts with a token ending with a separator +// - A footer ends when another footer is found or text ends +// +func getDefaultMessageBlockMap(txtBlock string, tokenSep []string) map[string][]shared.MessageBlock{ + msgBlockMap := make(map[string][]shared.MessageBlock) + footers := make([]string, 0) + body, footerBlock, line := "", "", "" + footerFound := false + // Look through each line + scanner := bufio.NewScanner(strings.NewReader(txtBlock)) + for scanner.Scan() { + line = scanner.Text() + if token, _ := findFooterToken(line, tokenSep); len(token) > 0 { + // if footer was already found from before + if len(footerBlock) > 0{ + footers = append(footers, strings.TrimSpace(footerBlock)) + } + footerFound = true + footerBlock = "" + } + + //'\n' is removed when reading from scanner + if !footerFound { + body += line + "\n" + }else{ + footerBlock += line + "\n" + } + } + if len(footerBlock) > 0 { + footers = append(footers, strings.TrimSpace(footerBlock)) + } + + body = strings.TrimSpace(body) + if len(body) > 0{ + msgBlockMap["body"] = []shared.MessageBlock {{ + Label: "", + Content: body, + } } + } + + footerBlocks := getMessageBlocksFromTexts(footers, tokenSep) + if len(footerBlocks) > 0 { + msgBlockMap["footer"] = footerBlocks + } + + return msgBlockMap +} \ No newline at end of file diff --git a/internal/analyzer/angular.go b/internal/analyzer/angular.go index cf9e348..71b3309 100644 --- a/internal/analyzer/angular.go +++ b/internal/analyzer/angular.go @@ -2,7 +2,7 @@ package analyzer import ( - "regexp" + "github.com/Nightapes/go-semantic-release/pkg/config" "strings" log "github.com/sirupsen/logrus" @@ -14,14 +14,16 @@ type angular struct { rules []Rule regex string log *log.Entry + config config.AnalyzerConfig } // ANGULAR identifier const ANGULAR = "angular" +var angularFooterTokenSep = defaultTokenSeparators func newAngular() *angular { return &angular{ - regex: `^(TAG)(?:\((.*)\))?: (?s)(.*)`, + regex: `^(?P\w*)(?:\((?P.*)\))?: (?P.*)`, log: log.WithField("analyzer", ANGULAR), rules: []Rule{ { @@ -87,39 +89,51 @@ func (a *angular) getRules() []Rule { } func (a *angular) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit { - re := regexp.MustCompile(strings.Replace(a.regex, "TAG", rule.Tag, -1)) - matches := re.FindStringSubmatch(commit.Message) - if matches == nil { + tokenSep := append(a.config.TokenSeparators, conventionalFooterTokenSep[:]...) + + firstSplit := strings.SplitN(commit.Message, "\n", 2) + header := firstSplit[0] + body := "" + if len(firstSplit) > 1 { + body = firstSplit[1] + } + matches := getRegexMatchedMap(a.regex, header) + + if len(matches) == 0 || matches["type"] != rule.Tag{ a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag) return nil } + msgBlockMap := getDefaultMessageBlockMap(body, tokenSep) + analyzed := &shared.AnalyzedCommit{ Commit: commit, Tag: rule.Tag, TagString: rule.TagString, - Scope: shared.Scope(matches[2]), + Scope: shared.Scope(matches["scope"]), + Subject: strings.TrimSpace(matches["subject"]), + MessageBlocks: msgBlockMap, } - message := strings.Join(matches[3:], "") - if !strings.Contains(message, "BREAKING CHANGE:") { - analyzed.ParsedMessage = strings.Trim(message, " ") + isBreaking := strings.Contains(commit.Message, defaultBreakingChangePrefix) + analyzed.IsBreaking = isBreaking + + oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body) + + if !isBreaking { + analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ") a.log.Tracef("%s: found %s", commit.Message, rule.Tag) return analyzed } a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message) - breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2) - - analyzed.IsBreaking = true + breakingChange := strings.SplitN(oldFormatMessage, defaultBreakingChangePrefix, 2) if len(breakingChange) > 1 { analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0]) analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1]) - - return analyzed + } else { + analyzed.ParsedBreakingChangeMessage = breakingChange[0] } - - analyzed.ParsedBreakingChangeMessage = breakingChange[0] return analyzed } diff --git a/internal/analyzer/angular_test.go b/internal/analyzer/angular_test.go index 527c2f6..07e818d 100644 --- a/internal/analyzer/angular_test.go +++ b/internal/analyzer/angular_test.go @@ -31,6 +31,8 @@ func TestAngular(t *testing.T) { Tag: "feat", TagString: "Features", Print: true, + Subject: "my first commit", + MessageBlocks: map[string][]shared.MessageBlock{}, }, }, "major": {}, @@ -60,6 +62,8 @@ func TestAngular(t *testing.T) { Tag: "feat", TagString: "Features", Print: true, + Subject: "my first commit", + MessageBlocks: map[string][]shared.MessageBlock{}, }, }, "major": { @@ -76,6 +80,8 @@ func TestAngular(t *testing.T) { Print: true, ParsedBreakingChangeMessage: "change api to v2", IsBreaking: true, + Subject: "my first break BREAKING CHANGE: change api to v2", + MessageBlocks: map[string][]shared.MessageBlock{}, }, }, "patch": {}, @@ -121,6 +127,8 @@ func TestAngular(t *testing.T) { Tag: "feat", TagString: "Features", Print: true, + Subject: "my first commit", + MessageBlocks: map[string][]shared.MessageBlock{}, }, }, "major": { @@ -137,6 +145,15 @@ func TestAngular(t *testing.T) { Print: true, ParsedBreakingChangeMessage: "change api to v2", IsBreaking: true, + Subject: "my first break", + MessageBlocks: map[string][]shared.MessageBlock{ + "footer": { + shared.MessageBlock{ + Label: "BREAKING CHANGE", + Content: "change api to v2", + }, + }, + }, }, }, "patch": {}, @@ -179,6 +196,8 @@ func TestAngular(t *testing.T) { Tag: "feat", TagString: "Features", Print: true, + Subject: "my first commit", + MessageBlocks: map[string][]shared.MessageBlock{}, }, }, "none": { @@ -194,6 +213,8 @@ func TestAngular(t *testing.T) { TagString: "Changes to CI/CD", Print: false, ParsedBreakingChangeMessage: "", + Subject: "my first build", + MessageBlocks: map[string][]shared.MessageBlock{}, }, }, "patch": {}, diff --git a/internal/analyzer/conventional.go b/internal/analyzer/conventional.go index 6dda122..66570fa 100644 --- a/internal/analyzer/conventional.go +++ b/internal/analyzer/conventional.go @@ -2,7 +2,6 @@ package analyzer import ( - "bufio" "github.com/Nightapes/go-semantic-release/pkg/config" "strings" @@ -107,7 +106,7 @@ func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.Analyzed return nil } - msgBlockMap := getConventionalMessageBlockMap(body, tokenSep) + msgBlockMap := getDefaultMessageBlockMap(body, tokenSep) analyzed := &shared.AnalyzedCommit{ Commit: commit, @@ -122,6 +121,7 @@ func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.Analyzed analyzed.IsBreaking = isBreaking oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body) + if !isBreaking { analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ") a.log.Tracef("%s: found %s", commit.Message, rule.Tag) @@ -141,50 +141,3 @@ func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.Analyzed return analyzed } -func getConventionalMessageBlockMap(txtBlock string, tokenSep []string) map[string][]shared.MessageBlock{ - msgBlockMap := make(map[string][]shared.MessageBlock) - footers := make([]string, 0) - body := "" - footerBlock := "" - line := "" - footerFound := false - // Look through each line - scanner := bufio.NewScanner(strings.NewReader(txtBlock)) - for scanner.Scan() { - line = scanner.Text() - if token, _ := findFooterToken(line, tokenSep); len(token) > 0 { - // if footer was already found from before - if len(footerBlock) > 0{ - footers = append(footers, strings.TrimSpace(footerBlock)) - } - footerFound = true - footerBlock = "" - } - - //'\n' is removed when reading from scanner - if !footerFound { - body += line + "\n" - }else{ - footerBlock += line + "\n" - } - } - if len(footerBlock) > 0 { - footers = append(footers, strings.TrimSpace(footerBlock)) - } - - body = strings.TrimSpace(body) - if len(body) > 0{ - msgBlockMap["body"] = []shared.MessageBlock {{ - Label: "", - Content: body, - } } - } - - footerBlocks := getMessageBlocksFromTexts(footers, tokenSep) - if len(footerBlocks) > 0 { - msgBlockMap["footer"] = footerBlocks - } - - - return msgBlockMap -}