From 45ed6e3ee29ace0acb516ad1fb168aad11cce404 Mon Sep 17 00:00:00 2001 From: tsuyoshiwada Date: Mon, 12 Mar 2018 00:09:47 +0900 Subject: [PATCH] feat: Add support for GitLab --- cmd/git-chglog/config.go | 37 ++++++++++++++ cmd/git-chglog/custom_template_builder.go | 4 +- cmd/git-chglog/kac_template_builder.go | 15 +++--- cmd/git-chglog/processor_factory.go | 5 ++ cmd/git-chglog/processor_factory_test.go | 36 +++++++++++++ cmd/git-chglog/variables.go | 2 + processor.go | 55 ++++++++++++++++++++ processor_test.go | 62 +++++++++++++++++++++++ 8 files changed, 209 insertions(+), 7 deletions(-) diff --git a/cmd/git-chglog/config.go b/cmd/git-chglog/config.go index e8aa5184..83f1a9ed 100644 --- a/cmd/git-chglog/config.go +++ b/cmd/git-chglog/config.go @@ -147,6 +147,43 @@ func (config *Config) normalizeStyleOfGitHub() { config.Options = opts } +// For GitLab +func (config *Config) normalizeStyleOfGitLab() { + opts := config.Options + + if len(opts.Issues.Prefix) == 0 { + opts.Issues.Prefix = []string{ + "#", + } + } + + if len(opts.Refs.Actions) == 0 { + opts.Refs.Actions = []string{ + "close", + "closes", + "closed", + "closing", + "fix", + "fixes", + "fixed", + "fixing", + "resolve", + "resolves", + "resolved", + "resolving", + } + } + + if opts.Merges.Pattern == "" && len(opts.Merges.PatternMaps) == 0 { + opts.Merges.Pattern = "^Merge branch '.*' into '(.*)'$" + opts.Merges.PatternMaps = []string{ + "Source", + } + } + + config.Options = opts +} + // Convert ... func (config *Config) Convert(ctx *CLIContext) *chglog.Config { info := config.Info diff --git a/cmd/git-chglog/custom_template_builder.go b/cmd/git-chglog/custom_template_builder.go index 90f7752f..48487cff 100644 --- a/cmd/git-chglog/custom_template_builder.go +++ b/cmd/git-chglog/custom_template_builder.go @@ -48,7 +48,7 @@ func (*customTemplateBuilderImpl) versionHeader(style, template string) string { // parts switch style { - case styleGitHub: + case styleGitHub, styleGitLab: tpl = "\n" tagName = "{{if .Tag.Previous}}[{{.Tag.Name}}]({{$.Info.RepositoryURL}}/compare/{{.Tag.Previous.Name}}...{{.Tag.Name}}){{else}}{{.Tag.Name}}{{end}}" } @@ -115,6 +115,8 @@ func (t *customTemplateBuilderImpl) merges(style string) string { switch style { case styleGitHub: title = "Pull Requests" + case styleGitLab: + title = "Merge Requests" default: title = "Merges" } diff --git a/cmd/git-chglog/kac_template_builder.go b/cmd/git-chglog/kac_template_builder.go index f31427cb..d929063a 100644 --- a/cmd/git-chglog/kac_template_builder.go +++ b/cmd/git-chglog/kac_template_builder.go @@ -47,7 +47,7 @@ func (t *kacTemplateBuilderImpl) versionHeader(style string) string { ) switch style { - case styleGitHub: + case styleGitHub, styleGitLab: tagName = "{{if .Tag.Previous}}[{{.Tag.Name}}]{{else}}{{.Tag.Name}}{{end}}" } @@ -87,6 +87,8 @@ func (t *kacTemplateBuilderImpl) merges(style string) string { switch style { case styleGitHub: title = "Pull Requests" + case styleGitLab: + title = "Merge Requests" default: title = "Merges" } @@ -107,12 +109,13 @@ func (*kacTemplateBuilderImpl) notes() string { } func (*kacTemplateBuilderImpl) footer(style string) string { - if style != styleGitHub { - return "" - } - - return `{{if .Versions}} + switch style { + case styleGitHub, styleGitLab: + return `{{if .Versions}} [Unreleased]: {{.Info.RepositoryURL}}/compare/{{$latest := index .Versions 0}}{{$latest.Tag.Name}}...HEAD{{range .Versions}}{{if .Tag.Previous}} [{{.Tag.Name}}]: {{$.Info.RepositoryURL}}/compare/{{.Tag.Previous.Name}}...{{.Tag.Name}}{{end}}{{end}} {{end}}` + default: + return "" + } } diff --git a/cmd/git-chglog/processor_factory.go b/cmd/git-chglog/processor_factory.go index dc43ea1e..7122c4a3 100644 --- a/cmd/git-chglog/processor_factory.go +++ b/cmd/git-chglog/processor_factory.go @@ -17,6 +17,7 @@ func NewProcessorFactory() *ProcessorFactory { return &ProcessorFactory{ hostRegistry: map[string]string{ "github": "github.com", + "gitlab": "gitlab.com", }, } } @@ -41,6 +42,10 @@ func (factory *ProcessorFactory) Create(config *Config) (chglog.Processor, error return &chglog.GitHubProcessor{ Host: fmt.Sprintf("%s://%s", obj.Scheme, obj.Host), }, nil + case "gitlab.com": + return &chglog.GitLabProcessor{ + Host: fmt.Sprintf("%s://%s", obj.Scheme, obj.Host), + }, nil default: return nil, nil } diff --git a/cmd/git-chglog/processor_factory_test.go b/cmd/git-chglog/processor_factory_test.go index 52072e18..32fd1234 100644 --- a/cmd/git-chglog/processor_factory_test.go +++ b/cmd/git-chglog/processor_factory_test.go @@ -56,3 +56,39 @@ func TestProcessorFactoryForGitHub(t *testing.T) { processor, ) } + +func TestProcessorFactoryForGitLab(t *testing.T) { + assert := assert.New(t) + factory := NewProcessorFactory() + + // gitlab.com + processor, err := factory.Create(&Config{ + Info: Info{ + RepositoryURL: "https://gitlab.com/owner/repo", + }, + }) + + assert.Nil(err) + assert.Equal( + &chglog.GitLabProcessor{ + Host: "https://gitlab.com", + }, + processor, + ) + + // self-hosted + processor, err = factory.Create(&Config{ + Style: "gitlab", + Info: Info{ + RepositoryURL: "https://original-gitserver.com/owner/repo", + }, + }) + + assert.Nil(err) + assert.Equal( + &chglog.GitLabProcessor{ + Host: "https://original-gitserver.com", + }, + processor, + ) +} diff --git a/cmd/git-chglog/variables.go b/cmd/git-chglog/variables.go index bcb63803..79cfb4b3 100644 --- a/cmd/git-chglog/variables.go +++ b/cmd/git-chglog/variables.go @@ -15,9 +15,11 @@ var ( // Styles var ( styleGitHub = "github" + styleGitLab = "gitlab" styleNone = "none" styles = []string{ styleGitHub, + styleGitLab, styleNone, } ) diff --git a/processor.go b/processor.go index f86d4e8c..d5da974f 100644 --- a/processor.go +++ b/processor.go @@ -65,3 +65,58 @@ func (p *GitHubProcessor) addLinks(input string) string { return input } + +// GitLabProcessor is optimized for CHANGELOG used in GitLab +// +// The following processing is performed +// - Mentions automatic link (@tsuyoshiwada -> [@tsuyoshiwada](https://gitlab.com/tsuyoshiwada)) +// - Automatic link to references (#123 -> [#123](https://gitlab.com/owner/repo/issues/123)) +type GitLabProcessor struct { + Host string // Host name used for link destination. Note: You must include the protocol (e.g. "https://gitlab.com") + config *Config + reMention *regexp.Regexp + reIssue *regexp.Regexp +} + +// Bootstrap ... +func (p *GitLabProcessor) Bootstrap(config *Config) { + p.config = config + + if p.Host == "" { + p.Host = "https://gitlab.com" + } else { + p.Host = strings.TrimRight(p.Host, "/") + } + + p.reMention = regexp.MustCompile("@(\\w+)") + p.reIssue = regexp.MustCompile("(?i)#(\\d+)") +} + +// ProcessCommit ... +func (p *GitLabProcessor) ProcessCommit(commit *Commit) *Commit { + commit.Header = p.addLinks(commit.Header) + commit.Subject = p.addLinks(commit.Subject) + commit.Body = p.addLinks(commit.Body) + + for _, note := range commit.Notes { + note.Body = p.addLinks(note.Body) + } + + if commit.Revert != nil { + commit.Revert.Header = p.addLinks(commit.Revert.Header) + } + + return commit +} + +func (p *GitLabProcessor) addLinks(input string) string { + repoURL := strings.TrimRight(p.config.Info.RepositoryURL, "/") + + // mentions + input = p.reMention.ReplaceAllString(input, "[@$1]("+p.Host+"/$1)") + + // issues + input = p.reIssue.ReplaceAllString(input, "[#$1]("+repoURL+"/issues/$1)") + + return input +} diff --git a/processor_test.go b/processor_test.go index 5c589f49..4a80b4b6 100644 --- a/processor_test.go +++ b/processor_test.go @@ -67,3 +67,65 @@ gh-56 hoge fuga`, ), ) } + +func TestGitLabProcessor(t *testing.T) { + assert := assert.New(t) + + config := &Config{ + Info: &Info{ + RepositoryURL: "https://example.com", + }, + } + + processor := &GitLabProcessor{} + + processor.Bootstrap(config) + + assert.Equal( + &Commit{ + Header: "message [@foo](https://gitlab.com/foo) [#123](https://example.com/issues/123)", + Subject: "message [@foo](https://gitlab.com/foo) [#123](https://example.com/issues/123)", + Body: `issue [#456](https://example.com/issues/456) +multiline [#789](https://example.com/issues/789) +[@foo](https://gitlab.com/foo), [@bar](https://gitlab.com/bar)`, + Notes: []*Note{ + &Note{ + Body: `issue1 [#11](https://example.com/issues/11) +issue2 [#22](https://example.com/issues/22) +gh-56 hoge fuga`, + }, + }, + }, + processor.ProcessCommit( + &Commit{ + Header: "message @foo #123", + Subject: "message @foo #123", + Body: `issue #456 +multiline #789 +@foo, @bar`, + Notes: []*Note{ + &Note{ + Body: `issue1 #11 +issue2 #22 +gh-56 hoge fuga`, + }, + }, + }, + ), + ) + + assert.Equal( + &Commit{ + Revert: &Revert{ + Header: "revert header [@mention](https://gitlab.com/mention) [#123](https://example.com/issues/123)", + }, + }, + processor.ProcessCommit( + &Commit{ + Revert: &Revert{ + Header: "revert header @mention #123", + }, + }, + ), + ) +}