You've already forked go-semantic-release
feat(angular): update angular to include new structured fields
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -90,21 +91,6 @@ func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.
|
|||||||
return analyzedCommits
|
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
|
// getRegexMatchedMap will match a regex with named groups and map the matching
|
||||||
// results to corresponding group names
|
// results to corresponding group names
|
||||||
@@ -162,3 +148,56 @@ func findFooterToken(text string, separators []string) (token string, sep string
|
|||||||
}
|
}
|
||||||
return "", ""
|
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
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -14,14 +14,16 @@ type angular struct {
|
|||||||
rules []Rule
|
rules []Rule
|
||||||
regex string
|
regex string
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
|
config config.AnalyzerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANGULAR identifier
|
// ANGULAR identifier
|
||||||
const ANGULAR = "angular"
|
const ANGULAR = "angular"
|
||||||
|
var angularFooterTokenSep = defaultTokenSeparators
|
||||||
|
|
||||||
func newAngular() *angular {
|
func newAngular() *angular {
|
||||||
return &angular{
|
return &angular{
|
||||||
regex: `^(TAG)(?:\((.*)\))?: (?s)(.*)`,
|
regex: `^(?P<type>\w*)(?:\((?P<scope>.*)\))?: (?P<subject>.*)`,
|
||||||
log: log.WithField("analyzer", ANGULAR),
|
log: log.WithField("analyzer", ANGULAR),
|
||||||
rules: []Rule{
|
rules: []Rule{
|
||||||
{
|
{
|
||||||
@@ -87,39 +89,51 @@ func (a *angular) getRules() []Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *angular) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit {
|
func (a *angular) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit {
|
||||||
re := regexp.MustCompile(strings.Replace(a.regex, "TAG", rule.Tag, -1))
|
tokenSep := append(a.config.TokenSeparators, conventionalFooterTokenSep[:]...)
|
||||||
matches := re.FindStringSubmatch(commit.Message)
|
|
||||||
if matches == nil {
|
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)
|
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msgBlockMap := getDefaultMessageBlockMap(body, tokenSep)
|
||||||
|
|
||||||
analyzed := &shared.AnalyzedCommit{
|
analyzed := &shared.AnalyzedCommit{
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
Tag: rule.Tag,
|
Tag: rule.Tag,
|
||||||
TagString: rule.TagString,
|
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:], "")
|
isBreaking := strings.Contains(commit.Message, defaultBreakingChangePrefix)
|
||||||
if !strings.Contains(message, "BREAKING CHANGE:") {
|
analyzed.IsBreaking = isBreaking
|
||||||
analyzed.ParsedMessage = strings.Trim(message, " ")
|
|
||||||
|
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
||||||
|
|
||||||
|
if !isBreaking {
|
||||||
|
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
||||||
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||||
return analyzed
|
return analyzed
|
||||||
}
|
}
|
||||||
|
|
||||||
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
||||||
breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2)
|
breakingChange := strings.SplitN(oldFormatMessage, defaultBreakingChangePrefix, 2)
|
||||||
|
|
||||||
analyzed.IsBreaking = true
|
|
||||||
|
|
||||||
if len(breakingChange) > 1 {
|
if len(breakingChange) > 1 {
|
||||||
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
||||||
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
||||||
|
} else {
|
||||||
return analyzed
|
|
||||||
}
|
|
||||||
|
|
||||||
analyzed.ParsedBreakingChangeMessage = breakingChange[0]
|
analyzed.ParsedBreakingChangeMessage = breakingChange[0]
|
||||||
|
}
|
||||||
return analyzed
|
return analyzed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": {},
|
"major": {},
|
||||||
@@ -60,6 +62,8 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": {
|
"major": {
|
||||||
@@ -76,6 +80,8 @@ func TestAngular(t *testing.T) {
|
|||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
IsBreaking: true,
|
IsBreaking: true,
|
||||||
|
Subject: "my first break BREAKING CHANGE: change api to v2",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": {},
|
"patch": {},
|
||||||
@@ -121,6 +127,8 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": {
|
"major": {
|
||||||
@@ -137,6 +145,15 @@ func TestAngular(t *testing.T) {
|
|||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
IsBreaking: true,
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": {},
|
"patch": {},
|
||||||
@@ -179,6 +196,8 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"none": {
|
"none": {
|
||||||
@@ -194,6 +213,8 @@ func TestAngular(t *testing.T) {
|
|||||||
TagString: "Changes to CI/CD",
|
TagString: "Changes to CI/CD",
|
||||||
Print: false,
|
Print: false,
|
||||||
ParsedBreakingChangeMessage: "",
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": {},
|
"patch": {},
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -107,7 +106,7 @@ func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.Analyzed
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msgBlockMap := getConventionalMessageBlockMap(body, tokenSep)
|
msgBlockMap := getDefaultMessageBlockMap(body, tokenSep)
|
||||||
|
|
||||||
analyzed := &shared.AnalyzedCommit{
|
analyzed := &shared.AnalyzedCommit{
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
@@ -122,6 +121,7 @@ func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.Analyzed
|
|||||||
analyzed.IsBreaking = isBreaking
|
analyzed.IsBreaking = isBreaking
|
||||||
|
|
||||||
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
||||||
|
|
||||||
if !isBreaking {
|
if !isBreaking {
|
||||||
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
||||||
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
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
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user