diff --git a/.sv4git.yml b/.sv4git.yml index 3f38617..192ca92 100644 --- a/.sv4git.yml +++ b/.sv4git.yml @@ -17,5 +17,6 @@ commit-message: footer: issue: key: issue + add-value-prefix: '#' issue: - regex: '#[0-9]+' + regex: '#?[0-9]+' diff --git a/Makefile b/Makefile index 368caae..32e63b5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: usage build test run tidy release release-all +.PHONY: usage build test test-coverage test-show-coverage run tidy release release-all OK_COLOR=\033[32;01m NO_COLOR=\033[0m @@ -18,6 +18,8 @@ BUILDARCH ?= amd64 BUILDENVS ?= CGO_ENABLED=0 GOOS=$(BUILDOS) GOARCH=$(BUILDARCH) BUILDFLAGS ?= -a -installsuffix cgo --ldflags '-X main.Version=$(VERSION) -extldflags "-lm -lstdc++ -static"' +COMPRESS_TYPE ?= targz + usage: Makefile @echo $(ECHOFLAGS) "to use make call:" @echo $(ECHOFLAGS) " make " @@ -35,6 +37,16 @@ test: @echo $(ECHOFLAGS) "$(OK_COLOR)==> Running tests...$(NO_COLOR)" @go test $(PKGS) +## test-coverage: run tests with coverage +test-coverage: + @echo $(ECHOFLAGS) "$(OK_COLOR)==> Running tests with coverage...$(NO_COLOR)" + @go test -race -covermode=atomic -coverprofile coverage.out ./... + +## test-show-coverage: show coverage +test-show-coverage: test-coverage + @echo $(ECHOFLAGS) "$(OK_COLOR)==> Show test coverage...$(NO_COLOR)" + @go tool cover -html coverage.out + ## run: run git-sv run: @echo $(ECHOFLAGS) "$(OK_COLOR)==> Running bin/$(BUILDOS)_$(BUILDARCH)/$(BIN)...$(NO_COLOR)" @@ -48,7 +60,11 @@ tidy: ## release: prepare binary for release release: make build +ifeq ($(COMPRESS_TYPE), zip) @zip -j bin/git-sv_$(VERSION)_$(BUILDOS)_$(BUILDARCH).zip bin/$(BUILDOS)_$(BUILDARCH)/$(BIN) +else + @tar -czf bin/git-sv_$(VERSION)_$(BUILDOS)_$(BUILDARCH).tar.gz -C bin/$(BUILDOS)_$(BUILDARCH)/ $(BIN) +endif ## release-all: prepare linux, darwin and windows binary for release (requires sv4git) release-all: @@ -56,4 +72,4 @@ release-all: VERSION=$(shell git sv nv) BUILDOS=linux make release VERSION=$(shell git sv nv) BUILDOS=darwin make release - VERSION=$(shell git sv nv) BUILDOS=windows make release + VERSION=$(shell git sv nv) COMPRESS_TYPE=zip BUILDOS=windows make release diff --git a/README.md b/README.md index 4bab651..8c6390c 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ commit-message: - Jira - JIRA use-hash: false # If false, use : separator. If true, use # separator. + add-value-prefix: '' # Add a prefix to issue value. issue: regex: '[A-Z]+-[0-9]+' # Regex for issue id. ``` diff --git a/sv/config.go b/sv/config.go index 4f86b10..d45aad0 100644 --- a/sv/config.go +++ b/sv/config.go @@ -25,9 +25,10 @@ type CommitMessageScopeConfig struct { // CommitMessageFooterConfig config footer metadata. type CommitMessageFooterConfig struct { - Key string `yaml:"key"` - KeySynonyms []string `yaml:"key-synonyms"` - UseHash bool `yaml:"use-hash"` + Key string `yaml:"key"` + KeySynonyms []string `yaml:"key-synonyms"` + UseHash bool `yaml:"use-hash"` + AddValuePrefix string `yaml:"add-value-prefix"` } // CommitMessageIssueConfig issue preferences. diff --git a/sv/message.go b/sv/message.go index b057a34..99f99bd 100644 --- a/sv/message.go +++ b/sv/message.go @@ -108,8 +108,7 @@ func (p MessageProcessorImpl) Enhance(branch string, message string) (string, er return "", fmt.Errorf("could not find issue id using configured regex") } - footer := fmt.Sprintf("%s: %s", p.messageCfg.IssueFooterConfig().Key, issue) - + footer := formatIssueFooter(p.messageCfg.IssueFooterConfig(), issue) if !hasFooter(message) { return "\n" + footer, nil } @@ -117,6 +116,16 @@ func (p MessageProcessorImpl) Enhance(branch string, message string) (string, er return footer, nil } +func formatIssueFooter(cfg CommitMessageFooterConfig, issue string) string { + if !strings.HasPrefix(issue, cfg.AddValuePrefix) { + issue = cfg.AddValuePrefix + issue + } + if cfg.UseHash { + return fmt.Sprintf("%s #%s", cfg.Key, strings.TrimPrefix(issue, "#")) + } + return fmt.Sprintf("%s: %s", cfg.Key, issue) +} + // IssueID try to extract issue id from branch, return empty if not found. func (p MessageProcessorImpl) IssueID(branch string) (string, error) { if p.branchesCfg.DisableIssue || p.messageCfg.Issue.Regex == "" { @@ -154,11 +163,7 @@ func (p MessageProcessorImpl) Format(msg CommitMessage) (string, string, string) if footer.Len() > 0 { footer.WriteString("\n") } - if p.messageCfg.IssueFooterConfig().UseHash { - footer.WriteString(fmt.Sprintf("%s #%s", p.messageCfg.IssueFooterConfig().Key, strings.TrimPrefix(issue, "#"))) - } else { - footer.WriteString(fmt.Sprintf("%s: %s", p.messageCfg.IssueFooterConfig().Key, issue)) - } + footer.WriteString(formatIssueFooter(p.messageCfg.IssueFooterConfig(), issue)) } return header.String(), msg.Body, footer.String() diff --git a/sv/message_test.go b/sv/message_test.go index ee78c8e..6e0f3c1 100644 --- a/sv/message_test.go +++ b/sv/message_test.go @@ -15,6 +15,25 @@ var ccfg = CommitMessageConfig{ Issue: CommitMessageIssueConfig{Regex: "[A-Z]+-[0-9]+"}, } +var ccfgHash = CommitMessageConfig{ + Types: []string{"feat", "fix"}, + Scope: CommitMessageScopeConfig{}, + Footer: map[string]CommitMessageFooterConfig{ + "issue": {Key: "jira", KeySynonyms: []string{"Jira"}, UseHash: true}, + "refs": {Key: "Refs", UseHash: true}, + }, + Issue: CommitMessageIssueConfig{Regex: "[A-Z]+-[0-9]+"}, +} + +var ccfgGitIssue = CommitMessageConfig{ + Types: []string{"feat", "fix"}, + Scope: CommitMessageScopeConfig{}, + Footer: map[string]CommitMessageFooterConfig{ + "issue": {Key: "issue", KeySynonyms: []string{"Issue"}, UseHash: false, AddValuePrefix: "#"}, + }, + Issue: CommitMessageIssueConfig{Regex: "#?[0-9]+"}, +} + var ccfgEmptyIssue = CommitMessageConfig{ Types: []string{"feat", "fix"}, Scope: CommitMessageScopeConfig{}, @@ -139,27 +158,30 @@ func TestMessageProcessorImpl_Validate(t *testing.T) { } func TestMessageProcessorImpl_Enhance(t *testing.T) { - p := NewMessageProcessor(ccfg, newBranchCfg(false)) - tests := []struct { name string + cfg CommitMessageConfig branch string message string want string wantErr bool }{ - {"issue on branch name", "JIRA-123", "fix: fix something", "\njira: JIRA-123", false}, - {"issue on branch name with description", "JIRA-123-some-description", "fix: fix something", "\njira: JIRA-123", false}, - {"issue on branch name with prefix", "feature/JIRA-123", "fix: fix something", "\njira: JIRA-123", false}, - {"with footer", "JIRA-123", fullMessage, "jira: JIRA-123", false}, - {"with issue on footer", "JIRA-123", fullMessageWithJira, "", false}, - {"issue on branch name with prefix and description", "feature/JIRA-123-some-description", "fix: fix something", "\njira: JIRA-123", false}, - {"no issue on branch name", "branch", "fix: fix something", "", true}, - {"unexpected branch name", "feature /JIRA-123", "fix: fix something", "", true}, + {"issue on branch name", ccfg, "JIRA-123", "fix: fix something", "\njira: JIRA-123", false}, + {"issue on branch name with description", ccfg, "JIRA-123-some-description", "fix: fix something", "\njira: JIRA-123", false}, + {"issue on branch name with prefix", ccfg, "feature/JIRA-123", "fix: fix something", "\njira: JIRA-123", false}, + {"with footer", ccfg, "JIRA-123", fullMessage, "jira: JIRA-123", false}, + {"with issue on footer", ccfg, "JIRA-123", fullMessageWithJira, "", false}, + {"issue on branch name with prefix and description", ccfg, "feature/JIRA-123-some-description", "fix: fix something", "\njira: JIRA-123", false}, + {"no issue on branch name", ccfg, "branch", "fix: fix something", "", true}, + {"unexpected branch name", ccfg, "feature /JIRA-123", "fix: fix something", "", true}, + {"issue on branch name using hash", ccfgHash, "JIRA-123-some-description", "fix: fix something", "\njira #JIRA-123", false}, + {"numeric issue on branch name", ccfgGitIssue, "#13", "fix: fix something", "\nissue: #13", false}, + {"numeric issue on branch name without hash", ccfgGitIssue, "13", "fix: fix something", "\nissue: #13", false}, + {"numeric issue on branch name with description without hash", ccfgGitIssue, "13-some-fix", "fix: fix something", "\nissue: #13", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := p.Enhance(tt.branch, tt.message) + got, err := NewMessageProcessor(tt.cfg, newBranchCfg(false)).Enhance(tt.branch, tt.message) if (err != nil) != tt.wantErr { t.Errorf("MessageProcessorImpl.Enhance() error = %v, wantErr %v", err, tt.wantErr) return @@ -325,12 +347,16 @@ func TestMessageProcessorImpl_Format(t *testing.T) { }{ {"simple message", ccfg, NewCommitMessage("feat", "", "something", "", "", ""), "feat: something", "", ""}, {"with issue", ccfg, NewCommitMessage("feat", "", "something", "", "JIRA-123", ""), "feat: something", "", "jira: JIRA-123"}, + {"with issue using hash", ccfgHash, NewCommitMessage("feat", "", "something", "", "JIRA-123", ""), "feat: something", "", "jira #JIRA-123"}, + {"with issue using double hash", ccfgHash, NewCommitMessage("feat", "", "something", "", "#JIRA-123", ""), "feat: something", "", "jira #JIRA-123"}, {"with breaking change", ccfg, NewCommitMessage("feat", "", "something", "", "", "breaks"), "feat: something", "", "BREAKING CHANGE: breaks"}, {"with scope", ccfg, NewCommitMessage("feat", "scope", "something", "", "", ""), "feat(scope): something", "", ""}, {"with body", ccfg, NewCommitMessage("feat", "", "something", "body", "", ""), "feat: something", "body", ""}, {"with multiline body", ccfg, NewCommitMessage("feat", "", "something", multilineBody, "", ""), "feat: something", multilineBody, ""}, {"full message", ccfg, NewCommitMessage("feat", "scope", "something", multilineBody, "JIRA-123", "breaks"), "feat(scope): something", multilineBody, fullFooter}, {"config without issue key", ccfgEmptyIssue, NewCommitMessage("feat", "", "something", "", "JIRA-123", ""), "feat: something", "", ""}, + {"with issue and issue prefix", ccfgGitIssue, NewCommitMessage("feat", "", "something", "", "123", ""), "feat: something", "", "issue: #123"}, + {"with #issue and issue prefix", ccfgGitIssue, NewCommitMessage("feat", "", "something", "", "#123", ""), "feat: something", "", "issue: #123"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {