From c865ad5731e7b5dd3f8d3b38ce3d6272cd212324 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Wed, 2 Mar 2022 09:20:50 +0100 Subject: [PATCH 01/15] feat: add an option for message selector issue: #45 --- sv/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/sv/config.go b/sv/config.go index af19378..694b815 100644 --- a/sv/config.go +++ b/sv/config.go @@ -5,6 +5,7 @@ package sv // CommitMessageConfig config a commit message. type CommitMessageConfig struct { Types []string `yaml:"types,flow"` + MessageSelector string `yaml:"selector"` Scope CommitMessageScopeConfig `yaml:"scope"` Footer map[string]CommitMessageFooterConfig `yaml:"footer"` Issue CommitMessageIssueConfig `yaml:"issue"` From 44895fa4a2737f4d9cb76bb4db4e386f85ff1849 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Wed, 2 Mar 2022 09:23:18 +0100 Subject: [PATCH 02/15] chore: update README with new option issue: #45 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b2c6d3e..6ecb2d2 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ branches: # Git branches config. commit-message: types: [build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test] # Supported commit types. + selector: '' # You can put in a regex here to select only a certain part of the commit message. scope: # Define supported scopes, if blank, scope will not be validated, if not, only scope listed will be valid. # Don't forget to add "" on your list if you need to define scopes and keep it optional. From 9d69abc45a29734a0960efe1c3ddffbd006e9096 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Thu, 3 Mar 2022 12:54:07 +0100 Subject: [PATCH 03/15] feat: ability to only select a subset of the message issue: #45 --- sv/message.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sv/message.go b/sv/message.go index 47adec8..b5eb5c5 100644 --- a/sv/message.go +++ b/sv/message.go @@ -202,7 +202,17 @@ func (p MessageProcessorImpl) Format(msg CommitMessage) (string, string, string) // Parse a commit message. func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { - commitType, scope, description, hasBreakingChange := parseSubjectMessage(subject) + + filteredSubject := subject + if p.messageCfg.MessageSelector != "" { + subjectRegex := regexp.MustCompile(p.messageCfg.MessageSelector) + subjectMessageIndex := regex.SubexpIndex("message") + subjectMatch := regex.FindStringSubmatch(subject) + + filteredSubject = subjectMatch[subjectMessageIndex] + } + + commitType, scope, description, hasBreakingChange := parseSubjectMessage(filteredSubject) metadata := make(map[string]string) for key, mdCfg := range p.messageCfg.Footer { From a1498c0832322f1bee956777742731f300ee0422 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Thu, 3 Mar 2022 12:59:09 +0100 Subject: [PATCH 04/15] chore: remove empty line issue: #45 --- sv/message.go | 1 - 1 file changed, 1 deletion(-) diff --git a/sv/message.go b/sv/message.go index b5eb5c5..709fb66 100644 --- a/sv/message.go +++ b/sv/message.go @@ -202,7 +202,6 @@ func (p MessageProcessorImpl) Format(msg CommitMessage) (string, string, string) // Parse a commit message. func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { - filteredSubject := subject if p.messageCfg.MessageSelector != "" { subjectRegex := regexp.MustCompile(p.messageCfg.MessageSelector) From 946024ce0b0a42290e483d7f3e1f56a7e306d0db Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Mon, 7 Mar 2022 11:19:00 +0100 Subject: [PATCH 05/15] fix: const usage and variable reference issue: #45 --- sv/message.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sv/message.go b/sv/message.go index 709fb66..57d1dad 100644 --- a/sv/message.go +++ b/sv/message.go @@ -11,6 +11,7 @@ const ( breakingChangeFooterKey = "BREAKING CHANGE" breakingChangeMetadataKey = "breaking-change" issueMetadataKey = "issue" + messageRegexGroupName = "message" ) // CommitMessage is a message using conventional commits. @@ -205,8 +206,8 @@ func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { filteredSubject := subject if p.messageCfg.MessageSelector != "" { subjectRegex := regexp.MustCompile(p.messageCfg.MessageSelector) - subjectMessageIndex := regex.SubexpIndex("message") - subjectMatch := regex.FindStringSubmatch(subject) + subjectMessageIndex := subjectRegex.SubexpIndex(messageRegexGroupName) + subjectMatch := subjectRegex.FindStringSubmatch(subject) filteredSubject = subjectMatch[subjectMessageIndex] } From b1b47747c1f324560cc1876bc7e908e925e31f40 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Mon, 7 Mar 2022 16:11:07 +0100 Subject: [PATCH 06/15] feat: possiblity to filter for relevant git tags issue: #45 --- README.md | 1 + sv/config.go | 1 + sv/git.go | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6ecb2d2..210c0dd 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ versioning: # versioning bump tag: pattern: '%d.%d.%d' # Pattern used to create git tag. + filter: '' # Enables you to filter for considerable tags using git pattern syntax release-notes: # Deprecated!!! please use 'sections' instead! diff --git a/sv/config.go b/sv/config.go index 694b815..64437cd 100644 --- a/sv/config.go +++ b/sv/config.go @@ -63,6 +63,7 @@ type VersioningConfig struct { // TagConfig tag preferences. type TagConfig struct { Pattern string `yaml:"pattern"` + Filter string `yaml:"filter"` } // ==== Release Notes ==== diff --git a/sv/git.go b/sv/git.go index 7474824..a15afa8 100644 --- a/sv/git.go +++ b/sv/git.go @@ -15,8 +15,8 @@ import ( ) const ( - logSeparator = "##" - endLine = "~~" + logSeparator = "###" + endLine = "~~~" ) // Git commands. @@ -144,7 +144,7 @@ func (g GitImpl) Tag(version semver.Version) (string, error) { // Tags list repository tags. func (g GitImpl) Tags() ([]GitTag, error) { - cmd := exec.Command("git", "for-each-ref", "--sort", "creatordate", "--format", "%(creatordate:iso8601)#%(refname:short)", "refs/tags") + cmd := exec.Command("git", "for-each-ref", "--sort", "creatordate", "--format", "%(creatordate:iso8601)#%(refname:short)", "refs/tags/" + g.tagCfg.Filter) out, err := cmd.CombinedOutput() if err != nil { return nil, combinedOutputErr(err, out) From cde390c838dcd775d92e4054d3eeb97c3e7542af Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Thu, 31 Mar 2022 15:53:53 +0200 Subject: [PATCH 07/15] chore: include feedback from pull request review issue: #45 --- README.md | 2 +- sv/config.go | 2 +- sv/message.go | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 210c0dd..726d651 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ branches: # Git branches config. commit-message: types: [build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test] # Supported commit types. - selector: '' # You can put in a regex here to select only a certain part of the commit message. + header-selector: '' # You can put in a regex here to select only a certain part of the commit message. Please define a regex group 'header'. scope: # Define supported scopes, if blank, scope will not be validated, if not, only scope listed will be valid. # Don't forget to add "" on your list if you need to define scopes and keep it optional. diff --git a/sv/config.go b/sv/config.go index 64437cd..264755b 100644 --- a/sv/config.go +++ b/sv/config.go @@ -5,7 +5,7 @@ package sv // CommitMessageConfig config a commit message. type CommitMessageConfig struct { Types []string `yaml:"types,flow"` - MessageSelector string `yaml:"selector"` + HeaderSelector string `yaml:"header-selector"` Scope CommitMessageScopeConfig `yaml:"scope"` Footer map[string]CommitMessageFooterConfig `yaml:"footer"` Issue CommitMessageIssueConfig `yaml:"issue"` diff --git a/sv/message.go b/sv/message.go index 57d1dad..1c96e52 100644 --- a/sv/message.go +++ b/sv/message.go @@ -11,7 +11,7 @@ const ( breakingChangeFooterKey = "BREAKING CHANGE" breakingChangeMetadataKey = "breaking-change" issueMetadataKey = "issue" - messageRegexGroupName = "message" + messageRegexGroupName = "header" ) // CommitMessage is a message using conventional commits. @@ -203,16 +203,13 @@ func (p MessageProcessorImpl) Format(msg CommitMessage) (string, string, string) // Parse a commit message. func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { - filteredSubject := subject - if p.messageCfg.MessageSelector != "" { - subjectRegex := regexp.MustCompile(p.messageCfg.MessageSelector) - subjectMessageIndex := subjectRegex.SubexpIndex(messageRegexGroupName) - subjectMatch := subjectRegex.FindStringSubmatch(subject) - - filteredSubject = subjectMatch[subjectMessageIndex] + preparedSubject, prepError := p.prepareHeader(subject) + + if prepError != nil { + fmt.Println(prepError) } - commitType, scope, description, hasBreakingChange := parseSubjectMessage(filteredSubject) + commitType, scope, description, hasBreakingChange := parseSubjectMessage(preparedSubject) metadata := make(map[string]string) for key, mdCfg := range p.messageCfg.Footer { @@ -241,6 +238,30 @@ func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { } } +func (p MessageProcessorImpl) prepareHeader(header string) (string, error) { + if p.messageCfg.HeaderSelector == "" { + return header, nil + } + + regex, err := regexp.Compile(p.messageCfg.HeaderSelector) + if err != nil { + return "", fmt.Errorf("invalid regex on header-selector %s, error: %s", p.messageCfg.HeaderSelector, err.Error()) + } + + index := regex.SubexpIndex(messageRegexGroupName) + if index < 0 { + return "", fmt.Errorf("could not find %s regex group on header-selector regex", messageRegexGroupName) + } + + match := regex.FindStringSubmatch(header) + + if match == nil || len(match) < index { + return "", fmt.Errorf("could not find %s regex group in match result for '%s'", messageRegexGroupName, header) + } + + return match[index], nil +} + func parseSubjectMessage(message string) (string, string, string, bool) { regex := regexp.MustCompile(`([a-z]+)(\((.*)\))?(!)?: (.*)`) result := regex.FindStringSubmatch(message) From dc37dbf520277fa7cfb0e13d003fd771896b891c Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Thu, 31 Mar 2022 15:57:22 +0200 Subject: [PATCH 08/15] chore: add new config options to default config issue: #45 --- cmd/git-sv/config.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/git-sv/config.go b/cmd/git-sv/config.go index 4bbd0e2..04fc14b 100644 --- a/cmd/git-sv/config.go +++ b/cmd/git-sv/config.go @@ -77,7 +77,10 @@ func defaultConfig() Config { UpdatePatch: []string{"build", "ci", "chore", "docs", "fix", "perf", "refactor", "style", "test"}, IgnoreUnknown: false, }, - Tag: sv.TagConfig{Pattern: "%d.%d.%d"}, + Tag: sv.TagConfig{ + Pattern: "%d.%d.%d", + Filter: "", + }, ReleaseNotes: sv.ReleaseNotesConfig{ Sections: []sv.ReleaseNotesSectionConfig{ {Name: "Features", SectionType: sv.ReleaseNotesSectionTypeCommits, CommitTypes: []string{"feat"}}, @@ -99,6 +102,7 @@ func defaultConfig() Config { "issue": {Key: "jira", KeySynonyms: []string{"Jira", "JIRA"}}, }, Issue: sv.CommitMessageIssueConfig{Regex: "[A-Z]+-[0-9]+"}, + HeaderSelector: "", }, } } From 2adacd62ef8827084903a75226ebf19657969e56 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Thu, 31 Mar 2022 16:31:05 +0200 Subject: [PATCH 09/15] test: add tests for header selector behaviour issue: #45 --- sv/message_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sv/message_test.go b/sv/message_test.go index e1f95d9..243c6df 100644 --- a/sv/message_test.go +++ b/sv/message_test.go @@ -62,6 +62,19 @@ func newBranchCfg(skipDetached bool) BranchesConfig { } } +func newCommitMessageCfg(headerSelector string) CommitMessageConfig { + return CommitMessageConfig{ + Types: []string{"feat", "fix"}, + Scope: CommitMessageScopeConfig{Values: []string{"", "scope"}}, + Footer: map[string]CommitMessageFooterConfig{ + "issue": {Key: "jira", KeySynonyms: []string{"Jira"}}, + "refs": {Key: "Refs", UseHash: true}, + }, + Issue: CommitMessageIssueConfig{Regex: "[A-Z]+-[0-9]+"}, + HeaderSelector: headerSelector, + } +} + // messages samples start. var fullMessage = `fix: correct minor typos in code @@ -506,3 +519,35 @@ func Test_parseSubjectMessage(t *testing.T) { }) } } + +func Test_prepareHeader(t *testing.T) { + tests := []struct { + name string + headerSelector string + commitHeader string + wantHeader string + wantError bool + }{ + {"conventional without selector", "", "feat: something", "feat: something", false}, + {"conventional with scope without selector", "", "feat(scope): something", "feat(scope): something", false}, + {"non-conventional without selector", "", "something", "something", false}, + {"matching conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "Merged PR 123: feat: something", "feat: something", false}, + {"matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "Merged PR 123: something", "something", false}, + {"matching non-conventional with selector without group", "Merged PR (\\d+): (.*)", "Merged PR 123: something", "", true}, + {"non-matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "something", "", true}, + {"matching non-conventional with invalid regex", "Merged PR (\\d+): (?
.*)", "Merged PR 123: something", "", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msgProcessor := NewMessageProcessor(newCommitMessageCfg(tt.headerSelector), newBranchCfg(false)) + header, err := msgProcessor.prepareHeader(tt.commitHeader) + + if tt.wantError && err == nil { + t.Errorf("prepareHeader() err got = %v, want not nil", err) + } + if header != tt.wantHeader { + t.Errorf("prepareHeader() header got = %v, want %v", header, tt.wantHeader) + } + }) + } +} From 00c843df2dda061f8a4f309f3b80906744ef5661 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Mon, 4 Apr 2022 08:25:17 +0200 Subject: [PATCH 10/15] fix: also apply tag filter to last tag fetching issue: #45 --- sv/git.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sv/git.go b/sv/git.go index a15afa8..4fb4ee0 100644 --- a/sv/git.go +++ b/sv/git.go @@ -82,8 +82,8 @@ func NewGit(messageProcessor MessageProcessor, cfg TagConfig) *GitImpl { } // LastTag get last tag, if no tag found, return empty. -func (GitImpl) LastTag() string { - cmd := exec.Command("git", "for-each-ref", "refs/tags", "--sort", "-creatordate", "--format", "%(refname:short)", "--count", "1") +func (g GitImpl) LastTag() string { + cmd := exec.Command("git", "for-each-ref", "refs/tags/" + g.tagCfg.Filter, "--sort", "-creatordate", "--format", "%(refname:short)", "--count", "1") out, err := cmd.CombinedOutput() if err != nil { return "" From c6aaac5638ee72804b9982689deab55da8b3331d Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Mon, 4 Apr 2022 08:55:29 +0200 Subject: [PATCH 11/15] refactor: add error handling for parsing messages issue: #45 --- sv/git.go | 18 ++++++++++++++---- sv/message.go | 16 ++++++++-------- sv/message_test.go | 4 ++-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/sv/git.go b/sv/git.go index 4fb4ee0..6c2e9b2 100644 --- a/sv/git.go +++ b/sv/git.go @@ -194,23 +194,33 @@ func parseLogOutput(messageProcessor MessageProcessor, log string) []GitCommitLo var logs []GitCommitLog for scanner.Scan() { if text := strings.TrimSpace(strings.Trim(scanner.Text(), "\"")); text != "" { - logs = append(logs, parseCommitLog(messageProcessor, text)) + log, err := parseCommitLog(messageProcessor, text) + // Ignore errors occuring during parsing + if err == nil { + logs = append(logs, log) + } } } return logs } -func parseCommitLog(messageProcessor MessageProcessor, commit string) GitCommitLog { +func parseCommitLog(messageProcessor MessageProcessor, commit string) (GitCommitLog, error) { content := strings.Split(strings.Trim(commit, "\""), logSeparator) timestamp, _ := strconv.Atoi(content[1]) + message, err := messageProcessor.Parse(content[4], content[5]) + + if err != nil { + return GitCommitLog{}, err + } + return GitCommitLog{ Date: content[0], Timestamp: timestamp, AuthorName: content[2], Hash: content[3], - Message: messageProcessor.Parse(content[4], content[5]), - } + Message: message, + }, nil } func splitAt(b []byte) func(data []byte, atEOF bool) (advance int, token []byte, err error) { diff --git a/sv/message.go b/sv/message.go index 1c96e52..2d9852f 100644 --- a/sv/message.go +++ b/sv/message.go @@ -56,7 +56,7 @@ type MessageProcessor interface { Enhance(branch string, message string) (string, error) IssueID(branch string) (string, error) Format(msg CommitMessage) (string, string, string) - Parse(subject, body string) CommitMessage + Parse(subject, body string) (CommitMessage, error) } // NewMessageProcessor MessageProcessorImpl constructor. @@ -81,7 +81,7 @@ func (p MessageProcessorImpl) SkipBranch(branch string, detached bool) bool { // Validate commit message. func (p MessageProcessorImpl) Validate(message string) error { subject, body := splitCommitMessageContent(message) - msg := p.Parse(subject, body) + msg, _ := p.Parse(subject, body) if !regexp.MustCompile(`^[a-z+]+(\(.+\))?!?: .+$`).MatchString(subject) { return fmt.Errorf("subject [%s] should be valid according with conventional commits", subject) @@ -202,11 +202,11 @@ func (p MessageProcessorImpl) Format(msg CommitMessage) (string, string, string) } // Parse a commit message. -func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { - preparedSubject, prepError := p.prepareHeader(subject) +func (p MessageProcessorImpl) Parse(subject, body string) (CommitMessage, error) { + preparedSubject, err := p.prepareHeader(subject) - if prepError != nil { - fmt.Println(prepError) + if err != nil { + return CommitMessage{}, err } commitType, scope, description, hasBreakingChange := parseSubjectMessage(preparedSubject) @@ -235,7 +235,7 @@ func (p MessageProcessorImpl) Parse(subject, body string) CommitMessage { Body: body, IsBreakingChange: hasBreakingChange, Metadata: metadata, - } + }, nil } func (p MessageProcessorImpl) prepareHeader(header string) (string, error) { @@ -256,7 +256,7 @@ func (p MessageProcessorImpl) prepareHeader(header string) (string, error) { match := regex.FindStringSubmatch(header) if match == nil || len(match) < index { - return "", fmt.Errorf("could not find %s regex group in match result for '%s'", messageRegexGroupName, header) + return header, nil } return match[index], nil diff --git a/sv/message_test.go b/sv/message_test.go index 243c6df..a7f4079 100644 --- a/sv/message_test.go +++ b/sv/message_test.go @@ -411,7 +411,7 @@ func TestMessageProcessorImpl_Parse(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := NewMessageProcessor(tt.cfg, newBranchCfg(false)).Parse(tt.subject, tt.body); !reflect.DeepEqual(got, tt.want) { + if got, err := NewMessageProcessor(tt.cfg, newBranchCfg(false)).Parse(tt.subject, tt.body); !reflect.DeepEqual(got, tt.want) && err == nil { t.Errorf("MessageProcessorImpl.Parse() = %v, want %v", got, tt.want) } }) @@ -534,7 +534,7 @@ func Test_prepareHeader(t *testing.T) { {"matching conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "Merged PR 123: feat: something", "feat: something", false}, {"matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "Merged PR 123: something", "something", false}, {"matching non-conventional with selector without group", "Merged PR (\\d+): (.*)", "Merged PR 123: something", "", true}, - {"non-matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "something", "", true}, + {"non-matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "something", "something", false}, {"matching non-conventional with invalid regex", "Merged PR (\\d+): (?
.*)", "Merged PR 123: something", "", true}, } for _, tt := range tests { From 25458f20f643c3a082f676fd67a504a779d71bba Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Mon, 4 Apr 2022 09:23:53 +0200 Subject: [PATCH 12/15] revert: "refactor: add error handling for parsing messages" This reverts commit c6aaac5638ee72804b9982689deab55da8b3331d. issue: #45 --- sv/message.go | 2 +- sv/message_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sv/message.go b/sv/message.go index 2d9852f..64b051b 100644 --- a/sv/message.go +++ b/sv/message.go @@ -256,7 +256,7 @@ func (p MessageProcessorImpl) prepareHeader(header string) (string, error) { match := regex.FindStringSubmatch(header) if match == nil || len(match) < index { - return header, nil + return "", fmt.Errorf("could not find %s regex group in match result for '%s'", messageRegexGroupName, header) } return match[index], nil diff --git a/sv/message_test.go b/sv/message_test.go index a7f4079..c1e790c 100644 --- a/sv/message_test.go +++ b/sv/message_test.go @@ -534,7 +534,7 @@ func Test_prepareHeader(t *testing.T) { {"matching conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "Merged PR 123: feat: something", "feat: something", false}, {"matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "Merged PR 123: something", "something", false}, {"matching non-conventional with selector without group", "Merged PR (\\d+): (.*)", "Merged PR 123: something", "", true}, - {"non-matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "something", "something", false}, + {"non-matching non-conventional with selector with group", "Merged PR (\\d+): (?P
.*)", "something", "", true}, {"matching non-conventional with invalid regex", "Merged PR (\\d+): (?
.*)", "Merged PR 123: something", "", true}, } for _, tt := range tests { From f36433692da9dd51901057758204af131a1b822a Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Wed, 6 Apr 2022 09:52:35 +0200 Subject: [PATCH 13/15] refactor: handle parse errors to the caller in validate issue: #45 --- sv/message.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sv/message.go b/sv/message.go index 64b051b..fc7e5f7 100644 --- a/sv/message.go +++ b/sv/message.go @@ -81,7 +81,11 @@ func (p MessageProcessorImpl) SkipBranch(branch string, detached bool) bool { // Validate commit message. func (p MessageProcessorImpl) Validate(message string) error { subject, body := splitCommitMessageContent(message) - msg, _ := p.Parse(subject, body) + msg, parseErr := p.Parse(subject, body) + + if (parseErr != nil) { + return parseErr + } if !regexp.MustCompile(`^[a-z+]+(\(.+\))?!?: .+$`).MatchString(subject) { return fmt.Errorf("subject [%s] should be valid according with conventional commits", subject) From 8bce43b1603d48e75a6e70708bbcad9345f6c850 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Wed, 6 Apr 2022 11:01:17 +0200 Subject: [PATCH 14/15] refactor: make handling with unconventional commits configurable issue: #45 --- README.md | 1 + cmd/git-sv/config.go | 1 + cmd/git-sv/main.go | 2 +- sv/config.go | 1 + sv/git.go | 22 ++++++++++++++++------ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 726d651..502504b 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ branches: # Git branches config. commit-message: types: [build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test] # Supported commit types. header-selector: '' # You can put in a regex here to select only a certain part of the commit message. Please define a regex group 'header'. + skip-unconventional: false # Allows to skip commits that do not comply with conventional commits. Otherwise those will cause errors. scope: # Define supported scopes, if blank, scope will not be validated, if not, only scope listed will be valid. # Don't forget to add "" on your list if you need to define scopes and keep it optional. diff --git a/cmd/git-sv/config.go b/cmd/git-sv/config.go index 04fc14b..b7a2f17 100644 --- a/cmd/git-sv/config.go +++ b/cmd/git-sv/config.go @@ -103,6 +103,7 @@ func defaultConfig() Config { }, Issue: sv.CommitMessageIssueConfig{Regex: "[A-Z]+-[0-9]+"}, HeaderSelector: "", + SkipUnconventional: false, }, } } diff --git a/cmd/git-sv/main.go b/cmd/git-sv/main.go index b2a4a02..56e1055 100644 --- a/cmd/git-sv/main.go +++ b/cmd/git-sv/main.go @@ -43,7 +43,7 @@ func main() { cfg := loadCfg(repoPath) messageProcessor := sv.NewMessageProcessor(cfg.CommitMessage, cfg.Branches) - git := sv.NewGit(messageProcessor, cfg.Tag) + git := sv.NewGit(messageProcessor, cfg.Tag, cfg.CommitMessage) semverProcessor := sv.NewSemVerCommitsProcessor(cfg.Versioning, cfg.CommitMessage) releasenotesProcessor := sv.NewReleaseNoteProcessor(cfg.ReleaseNotes) outputFormatter := sv.NewOutputFormatter(templateFS(filepath.Join(repoPath, configDir, "templates"))) diff --git a/sv/config.go b/sv/config.go index 264755b..617d84b 100644 --- a/sv/config.go +++ b/sv/config.go @@ -9,6 +9,7 @@ type CommitMessageConfig struct { Scope CommitMessageScopeConfig `yaml:"scope"` Footer map[string]CommitMessageFooterConfig `yaml:"footer"` Issue CommitMessageIssueConfig `yaml:"issue"` + SkipUnconventional bool `yaml:"skip-unconventional"` } // IssueFooterConfig config for issue. diff --git a/sv/git.go b/sv/git.go index 6c2e9b2..0ee0a5f 100644 --- a/sv/git.go +++ b/sv/git.go @@ -71,13 +71,15 @@ func NewLogRange(t LogRangeType, start, end string) LogRange { type GitImpl struct { messageProcessor MessageProcessor tagCfg TagConfig + messageCfg CommitMessageConfig } // NewGit constructor. -func NewGit(messageProcessor MessageProcessor, cfg TagConfig) *GitImpl { +func NewGit(messageProcessor MessageProcessor, tagCfg TagConfig, messageCfg CommitMessageConfig) *GitImpl { return &GitImpl{ messageProcessor: messageProcessor, - tagCfg: cfg, + tagCfg: tagCfg, + messageCfg: messageCfg, } } @@ -114,7 +116,14 @@ func (g GitImpl) Log(lr LogRange) ([]GitCommitLog, error) { if err != nil { return nil, combinedOutputErr(err, out) } - return parseLogOutput(g.messageProcessor, string(out)), nil + + logs, parseErr := g.parseLogOutput(g.messageProcessor, string(out)) + + if parseErr != nil { + return nil, parseErr + } + + return logs, nil } // Commit runs git commit. @@ -188,20 +197,21 @@ func parseTagsOutput(input string) ([]GitTag, error) { return result, nil } -func parseLogOutput(messageProcessor MessageProcessor, log string) []GitCommitLog { +func (g GitImpl) parseLogOutput(messageProcessor MessageProcessor, log string) ([]GitCommitLog, error) { scanner := bufio.NewScanner(strings.NewReader(log)) scanner.Split(splitAt([]byte(endLine))) var logs []GitCommitLog for scanner.Scan() { if text := strings.TrimSpace(strings.Trim(scanner.Text(), "\"")); text != "" { log, err := parseCommitLog(messageProcessor, text) - // Ignore errors occuring during parsing if err == nil { logs = append(logs, log) + } else if !g.messageCfg.SkipUnconventional { + return logs, err } } } - return logs + return logs, nil } func parseCommitLog(messageProcessor MessageProcessor, commit string) (GitCommitLog, error) { From 7073cee8b3eea00d330cb9ebb4657accef2e5e32 Mon Sep 17 00:00:00 2001 From: hypervtechnics Date: Thu, 7 Apr 2022 11:12:14 +0200 Subject: [PATCH 15/15] refactor: revert "make handling with unconventional commits configurable" issue: #45 --- README.md | 1 - cmd/git-sv/config.go | 1 - cmd/git-sv/main.go | 2 +- sv/config.go | 1 - sv/git.go | 20 +++++++------------- 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 502504b..726d651 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,6 @@ branches: # Git branches config. commit-message: types: [build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test] # Supported commit types. header-selector: '' # You can put in a regex here to select only a certain part of the commit message. Please define a regex group 'header'. - skip-unconventional: false # Allows to skip commits that do not comply with conventional commits. Otherwise those will cause errors. scope: # Define supported scopes, if blank, scope will not be validated, if not, only scope listed will be valid. # Don't forget to add "" on your list if you need to define scopes and keep it optional. diff --git a/cmd/git-sv/config.go b/cmd/git-sv/config.go index b7a2f17..04fc14b 100644 --- a/cmd/git-sv/config.go +++ b/cmd/git-sv/config.go @@ -103,7 +103,6 @@ func defaultConfig() Config { }, Issue: sv.CommitMessageIssueConfig{Regex: "[A-Z]+-[0-9]+"}, HeaderSelector: "", - SkipUnconventional: false, }, } } diff --git a/cmd/git-sv/main.go b/cmd/git-sv/main.go index 56e1055..b2a4a02 100644 --- a/cmd/git-sv/main.go +++ b/cmd/git-sv/main.go @@ -43,7 +43,7 @@ func main() { cfg := loadCfg(repoPath) messageProcessor := sv.NewMessageProcessor(cfg.CommitMessage, cfg.Branches) - git := sv.NewGit(messageProcessor, cfg.Tag, cfg.CommitMessage) + git := sv.NewGit(messageProcessor, cfg.Tag) semverProcessor := sv.NewSemVerCommitsProcessor(cfg.Versioning, cfg.CommitMessage) releasenotesProcessor := sv.NewReleaseNoteProcessor(cfg.ReleaseNotes) outputFormatter := sv.NewOutputFormatter(templateFS(filepath.Join(repoPath, configDir, "templates"))) diff --git a/sv/config.go b/sv/config.go index 617d84b..264755b 100644 --- a/sv/config.go +++ b/sv/config.go @@ -9,7 +9,6 @@ type CommitMessageConfig struct { Scope CommitMessageScopeConfig `yaml:"scope"` Footer map[string]CommitMessageFooterConfig `yaml:"footer"` Issue CommitMessageIssueConfig `yaml:"issue"` - SkipUnconventional bool `yaml:"skip-unconventional"` } // IssueFooterConfig config for issue. diff --git a/sv/git.go b/sv/git.go index 0ee0a5f..70605e7 100644 --- a/sv/git.go +++ b/sv/git.go @@ -71,15 +71,13 @@ func NewLogRange(t LogRangeType, start, end string) LogRange { type GitImpl struct { messageProcessor MessageProcessor tagCfg TagConfig - messageCfg CommitMessageConfig } // NewGit constructor. -func NewGit(messageProcessor MessageProcessor, tagCfg TagConfig, messageCfg CommitMessageConfig) *GitImpl { +func NewGit(messageProcessor MessageProcessor, cfg TagConfig) *GitImpl { return &GitImpl{ messageProcessor: messageProcessor, - tagCfg: tagCfg, - messageCfg: messageCfg, + tagCfg: cfg, } } @@ -116,13 +114,10 @@ func (g GitImpl) Log(lr LogRange) ([]GitCommitLog, error) { if err != nil { return nil, combinedOutputErr(err, out) } - - logs, parseErr := g.parseLogOutput(g.messageProcessor, string(out)) - + logs, parseErr := parseLogOutput(g.messageProcessor, string(out)) if parseErr != nil { return nil, parseErr } - return logs, nil } @@ -197,18 +192,17 @@ func parseTagsOutput(input string) ([]GitTag, error) { return result, nil } -func (g GitImpl) parseLogOutput(messageProcessor MessageProcessor, log string) ([]GitCommitLog, error) { +func parseLogOutput(messageProcessor MessageProcessor, log string) ([]GitCommitLog, error) { scanner := bufio.NewScanner(strings.NewReader(log)) scanner.Split(splitAt([]byte(endLine))) var logs []GitCommitLog for scanner.Scan() { if text := strings.TrimSpace(strings.Trim(scanner.Text(), "\"")); text != "" { log, err := parseCommitLog(messageProcessor, text) - if err == nil { - logs = append(logs, log) - } else if !g.messageCfg.SkipUnconventional { - return logs, err + if err != nil { + return nil, err } + logs = append(logs, log) } } return logs, nil