From ed6fb2722ea84db8b9349d1bff61285cf5c0878d Mon Sep 17 00:00:00 2001 From: tsuyoshiwada Date: Fri, 2 Mar 2018 00:51:56 +0900 Subject: [PATCH] feat: Add template for `Keep a changelog` to the `--init` option --- cmd/git-chglog/custom_template_builder.go | 136 +++++++++++++++++ ...est.go => custom_template_builder_test.go} | 34 ++--- cmd/git-chglog/initializer.go | 32 ++-- cmd/git-chglog/initializer_test.go | 4 +- cmd/git-chglog/kac_template_builder.go | 118 +++++++++++++++ cmd/git-chglog/kac_template_builder_test.go | 42 ++++++ cmd/git-chglog/main.go | 2 +- cmd/git-chglog/template_builder.go | 137 +----------------- cmd/git-chglog/variables.go | 8 +- 9 files changed, 344 insertions(+), 169 deletions(-) create mode 100644 cmd/git-chglog/custom_template_builder.go rename cmd/git-chglog/{template_builder_test.go => custom_template_builder_test.go} (85%) create mode 100644 cmd/git-chglog/kac_template_builder.go create mode 100644 cmd/git-chglog/kac_template_builder_test.go diff --git a/cmd/git-chglog/custom_template_builder.go b/cmd/git-chglog/custom_template_builder.go new file mode 100644 index 00000000..90f7752f --- /dev/null +++ b/cmd/git-chglog/custom_template_builder.go @@ -0,0 +1,136 @@ +package main + +import "fmt" + +type customTemplateBuilderImpl struct{} + +// NewCustomTemplateBuilder ... +func NewCustomTemplateBuilder() TemplateBuilder { + return &customTemplateBuilderImpl{} +} + +// Build ... +func (t *customTemplateBuilderImpl) Build(ans *Answer) (string, error) { + // versions + tpl := "{{range .Versions}}\n" + + // version header + tpl += t.versionHeader(ans.Style, ans.Template) + + // commits + tpl += t.commits(ans.Template, ans.CommitMessageFormat) + + // revert + if ans.IncludeReverts { + tpl += t.reverts() + } + + // merges + if ans.IncludeMerges { + tpl += t.merges(ans.Style) + } + + // notes + tpl += t.notes() + + // versions end + tpl += "\n{{end}}" + + return tpl, nil +} + +func (*customTemplateBuilderImpl) versionHeader(style, template string) string { + var ( + tpl string + tagName = "{{.Tag.Name}}" + date = "{{datetime \"2006-01-02\" .Tag.Date}}" + ) + + // parts + switch style { + case styleGitHub: + tpl = "\n" + tagName = "{{if .Tag.Previous}}[{{.Tag.Name}}]({{$.Info.RepositoryURL}}/compare/{{.Tag.Previous.Name}}...{{.Tag.Name}}){{else}}{{.Tag.Name}}{{end}}" + } + + // format + switch template { + case tplStandard: + tpl = fmt.Sprintf("%s## %s (%s)\n", + tpl, + tagName, + date, + ) + case tplCool: + tpl = fmt.Sprintf("%s## %s\n\n> %s\n", + tpl, + tagName, + date, + ) + } + + return tpl +} + +func (*customTemplateBuilderImpl) commits(template, format string) string { + var ( + header string + body string + ) + + switch format { + case fmtSubject.Display: + body = `{{range .Commits}} +* {{.Header}}{{end}} +` + + default: + if format == fmtTypeScopeSubject.Display { + header = "{{if .Scope}}**{{.Scope}}:** {{end}}{{.Subject}}" + } else { + header = "{{.Subject}}" + } + + body = fmt.Sprintf(`### {{.Title}} +{{range .Commits}} +* %s{{end}} +`, header) + } + + return fmt.Sprintf(`{{range .CommitGroups}} +%s{{end}}`, body) +} + +func (*customTemplateBuilderImpl) reverts() string { + return `{{if .RevertCommits}} +### Reverts +{{range .RevertCommits}} +* {{.Revert.Header}}{{end}} +{{end}}` +} + +func (t *customTemplateBuilderImpl) merges(style string) string { + var title string + + switch style { + case styleGitHub: + title = "Pull Requests" + default: + title = "Merges" + } + + return fmt.Sprintf(`{{if .MergeCommits}} +### %s +{{range .MergeCommits}} +* {{.Header}}{{end}} +{{end}}`, title) +} + +func (*customTemplateBuilderImpl) notes() string { + return `{{range .NoteGroups}} +### {{.Title}} +{{range .Notes}} +{{.Body}} +{{end}} +{{end}}` +} diff --git a/cmd/git-chglog/template_builder_test.go b/cmd/git-chglog/custom_template_builder_test.go similarity index 85% rename from cmd/git-chglog/template_builder_test.go rename to cmd/git-chglog/custom_template_builder_test.go index 9d6449e0..a6251800 100644 --- a/cmd/git-chglog/template_builder_test.go +++ b/cmd/git-chglog/custom_template_builder_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/assert" ) -func TestTemplateBuilderDefault(t *testing.T) { +func TestCustomTemplateBuilderDefault(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleGitHub, @@ -25,7 +25,7 @@ func TestTemplateBuilderDefault(t *testing.T) { {{range .CommitGroups}} ### {{.Title}} {{range .Commits}} -* {{if ne .Scope ""}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} +* {{if .Scope}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} {{end}}{{if .RevertCommits}} ### Reverts {{range .RevertCommits}} @@ -43,9 +43,9 @@ func TestTemplateBuilderDefault(t *testing.T) { {{end}}`, out) } -func TestTemplateBuilderNone(t *testing.T) { +func TestCustomTemplateBuilderNone(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleNone, @@ -61,7 +61,7 @@ func TestTemplateBuilderNone(t *testing.T) { {{range .CommitGroups}} ### {{.Title}} {{range .Commits}} -* {{if ne .Scope ""}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} +* {{if .Scope}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} {{end}}{{if .RevertCommits}} ### Reverts {{range .RevertCommits}} @@ -79,9 +79,9 @@ func TestTemplateBuilderNone(t *testing.T) { {{end}}`, out) } -func TestTemplateBuilderCool(t *testing.T) { +func TestCustomTemplateBuilderCool(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleNone, @@ -99,7 +99,7 @@ func TestTemplateBuilderCool(t *testing.T) { {{range .CommitGroups}} ### {{.Title}} {{range .Commits}} -* {{if ne .Scope ""}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} +* {{if .Scope}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} {{end}}{{if .RevertCommits}} ### Reverts {{range .RevertCommits}} @@ -117,9 +117,9 @@ func TestTemplateBuilderCool(t *testing.T) { {{end}}`, out) } -func TestTemplateBuilderSubjectOnly(t *testing.T) { +func TestCustomTemplateBuilderSubjectOnly(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleNone, @@ -152,9 +152,9 @@ func TestTemplateBuilderSubjectOnly(t *testing.T) { {{end}}`, out) } -func TestTemplateBuilderSubject(t *testing.T) { +func TestCustomTemplateBuilderSubject(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleNone, @@ -188,9 +188,9 @@ func TestTemplateBuilderSubject(t *testing.T) { {{end}}`, out) } -func TestTemplateBuilderIgnoreReverts(t *testing.T) { +func TestCustomTemplateBuilderIgnoreReverts(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleNone, @@ -220,9 +220,9 @@ func TestTemplateBuilderIgnoreReverts(t *testing.T) { {{end}}`, out) } -func TestTemplateBuilderIgnoreMerges(t *testing.T) { +func TestCustomTemplateBuilderIgnoreMerges(t *testing.T) { assert := assert.New(t) - builder := NewTemplateBuilder() + builder := NewCustomTemplateBuilder() out, err := builder.Build(&Answer{ Style: styleNone, diff --git a/cmd/git-chglog/initializer.go b/cmd/git-chglog/initializer.go index 920df14b..7356f8b0 100644 --- a/cmd/git-chglog/initializer.go +++ b/cmd/git-chglog/initializer.go @@ -10,13 +10,13 @@ import ( // Initializer ... type Initializer struct { - ctx *InitContext - client gitcmd.Client - fs FileSystem - logger *Logger - questioner Questioner - configBuilder ConfigBuilder - templateBuilder TemplateBuilder + ctx *InitContext + client gitcmd.Client + fs FileSystem + logger *Logger + questioner Questioner + configBuilder ConfigBuilder + templateBuilderFactory TemplateBuilderFactory } // NewInitializer ... @@ -25,15 +25,14 @@ func NewInitializer( fs FileSystem, questioner Questioner, configBuilder ConfigBuilder, - templateBuilder TemplateBuilder, -) *Initializer { + tplBuilderFactory TemplateBuilderFactory) *Initializer { return &Initializer{ - ctx: ctx, - fs: fs, - logger: NewLogger(ctx.Stdout, ctx.Stderr, false, false), - questioner: questioner, - configBuilder: configBuilder, - templateBuilder: templateBuilder, + ctx: ctx, + fs: fs, + logger: NewLogger(ctx.Stdout, ctx.Stderr, false, false), + questioner: questioner, + configBuilder: configBuilder, + templateBuilderFactory: tplBuilderFactory, } } @@ -86,7 +85,8 @@ func (init *Initializer) generateConfig(ans *Answer) error { } func (init *Initializer) generateTemplate(ans *Answer) error { - s, err := init.templateBuilder.Build(ans) + templateBuilder := init.templateBuilderFactory(ans.Template) + s, err := templateBuilder.Build(ans) if err != nil { return err } diff --git a/cmd/git-chglog/initializer_test.go b/cmd/git-chglog/initializer_test.go index 5c4717c4..fb929f19 100644 --- a/cmd/git-chglog/initializer_test.go +++ b/cmd/git-chglog/initializer_test.go @@ -64,7 +64,9 @@ func TestInitializer(t *testing.T) { mockFs, questioner, configBuilder, - tplBuilder, + func(t string) TemplateBuilder { + return tplBuilder + }, ) assert.Equal(ExitCodeOK, init.Run()) diff --git a/cmd/git-chglog/kac_template_builder.go b/cmd/git-chglog/kac_template_builder.go new file mode 100644 index 00000000..f31427cb --- /dev/null +++ b/cmd/git-chglog/kac_template_builder.go @@ -0,0 +1,118 @@ +package main + +import "fmt" + +type kacTemplateBuilderImpl struct{} + +// NewKACTemplateBuilder ... +func NewKACTemplateBuilder() TemplateBuilder { + return &kacTemplateBuilderImpl{} +} + +// Build ... +func (t *kacTemplateBuilderImpl) Build(ans *Answer) (string, error) { + // versions + tpl := "## {{if .Versions}}[Unreleased]{{end}}\n{{range .Versions}}\n" + tpl += t.versionHeader(ans.Style) + + // commits + tpl += t.commits(ans.CommitMessageFormat) + + // revert + if ans.IncludeReverts { + tpl += t.reverts() + } + + // merges + if ans.IncludeMerges { + tpl += t.merges(ans.Style) + } + + // notes + tpl += t.notes() + + // versions end + tpl += "{{end}}" + + // footer (links) + tpl += t.footer(ans.Style) + + return tpl, nil +} + +func (t *kacTemplateBuilderImpl) versionHeader(style string) string { + var ( + tagName = "{{.Tag.Name}}" + date = "{{datetime \"2006-01-02\" .Tag.Date}}" + ) + + switch style { + case styleGitHub: + tagName = "{{if .Tag.Previous}}[{{.Tag.Name}}]{{else}}{{.Tag.Name}}{{end}}" + } + + return fmt.Sprintf("## %s - %s", tagName, date) +} + +func (t *kacTemplateBuilderImpl) commits(format string) string { + var ( + body string + ) + + switch format { + case fmtSubject.Display: + body = `{{range .Commits}} +- {{.Header}}{{end}}` + + default: + body = `### {{.Title}}{{range .Commits}} +- {{if .Scope}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}}` + } + + return fmt.Sprintf(`{{range .CommitGroups}} +%s +{{end}}`, body) +} + +func (t *kacTemplateBuilderImpl) reverts() string { + return `{{if .RevertCommits}} +### Reverts{{range .RevertCommits}} +- {{.Revert.Header}}{{end}} +{{end}}` +} + +func (t *kacTemplateBuilderImpl) merges(style string) string { + var title string + + switch style { + case styleGitHub: + title = "Pull Requests" + default: + title = "Merges" + } + + return fmt.Sprintf(`{{if .MergeCommits}} +### %s{{range .MergeCommits}} +- {{.Header}}{{end}} +{{end}}`, title) +} + +func (*kacTemplateBuilderImpl) notes() string { + return `{{range .NoteGroups}} +### {{.Title}} +{{range .Notes}} +{{.Body}} +{{end}} +{{end}}` +} + +func (*kacTemplateBuilderImpl) footer(style string) string { + if style != styleGitHub { + return "" + } + + 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}}` +} diff --git a/cmd/git-chglog/kac_template_builder_test.go b/cmd/git-chglog/kac_template_builder_test.go new file mode 100644 index 00000000..2f46d53f --- /dev/null +++ b/cmd/git-chglog/kac_template_builder_test.go @@ -0,0 +1,42 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestKACTemplateBuilderDefault(t *testing.T) { + assert := assert.New(t) + builder := NewKACTemplateBuilder() + + out, err := builder.Build(&Answer{ + Style: styleGitHub, + CommitMessageFormat: fmtTypeScopeSubject.Display, + Template: tplKeepAChangelog, + IncludeMerges: true, + IncludeReverts: true, + }) + + assert.Nil(err) + assert.Equal(`## {{if .Versions}}[Unreleased]{{end}} +{{range .Versions}} +## {{if .Tag.Previous}}[{{.Tag.Name}}]{{else}}{{.Tag.Name}}{{end}} - {{datetime "2006-01-02" .Tag.Date}}{{range .CommitGroups}} +### {{.Title}}{{range .Commits}} +- {{if .Scope}}**{{.Scope}}:** {{end}}{{.Subject}}{{end}} +{{end}}{{if .RevertCommits}} +### Reverts{{range .RevertCommits}} +- {{.Revert.Header}}{{end}} +{{end}}{{if .MergeCommits}} +### Pull Requests{{range .MergeCommits}} +- {{.Header}}{{end}} +{{end}}{{range .NoteGroups}} +### {{.Title}} +{{range .Notes}} +{{.Body}} +{{end}} +{{end}}{{end}}{{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}}`, out) +} diff --git a/cmd/git-chglog/main.go b/cmd/git-chglog/main.go index fb8e0c21..cae9214d 100644 --- a/cmd/git-chglog/main.go +++ b/cmd/git-chglog/main.go @@ -132,7 +132,7 @@ func main() { fs, ), NewConfigBuilder(), - NewTemplateBuilder(), + templateBuilderFactory, ) os.Exit(initializer.Run()) diff --git a/cmd/git-chglog/template_builder.go b/cmd/git-chglog/template_builder.go index 7154c0f3..963aab7c 100644 --- a/cmd/git-chglog/template_builder.go +++ b/cmd/git-chglog/template_builder.go @@ -1,143 +1,18 @@ package main -import "fmt" - // TemplateBuilder ... type TemplateBuilder interface { Builder } -type templateBuilderImpl struct{} +// TemplateBuilderFactory ... +type TemplateBuilderFactory = func(string) TemplateBuilder -// NewTemplateBuilder ... -func NewTemplateBuilder() TemplateBuilder { - return &templateBuilderImpl{} -} - -// Build ... -func (t *templateBuilderImpl) Build(ans *Answer) (string, error) { - // versions - tpl := "{{range .Versions}}\n" - - // version header - tpl += t.versionHeader(ans.Style, ans.Template) - - // commits - tpl += t.commits(ans.Template, ans.CommitMessageFormat) - - // revert - if ans.IncludeReverts { - tpl += t.reverts() - } - - // merges - if ans.IncludeMerges { - tpl += t.merges(ans.Style) - } - - // notes - tpl += t.notes() - - // versions end - tpl += "\n{{end}}" - - return tpl, nil -} - -func (*templateBuilderImpl) versionHeader(style, template string) string { - var ( - tpl string - tagName string - date = "{{datetime \"2006-01-02\" .Tag.Date}}" - ) - - // parts - switch style { - case styleGitHub: - tpl = "\n" - tagName = "{{if .Tag.Previous}}[{{.Tag.Name}}]({{$.Info.RepositoryURL}}/compare/{{.Tag.Previous.Name}}...{{.Tag.Name}}){{else}}{{.Tag.Name}}{{end}}" - default: - tagName = "{{.Tag.Name}}" - } - - // format +func templateBuilderFactory(template string) TemplateBuilder { switch template { - case tplStandard: - tpl = fmt.Sprintf("%s## %s (%s)\n", - tpl, - tagName, - date, - ) - case tplCool: - tpl = fmt.Sprintf("%s## %s\n\n> %s\n", - tpl, - tagName, - date, - ) - } - - return tpl -} - -func (*templateBuilderImpl) commits(template, format string) string { - var ( - header string - body string - ) - - switch format { - case fmtSubject.Display: - body = `{{range .Commits}} -* {{.Header}}{{end}} -` - + case tplKeepAChangelog: + return NewKACTemplateBuilder() default: - if format == fmtTypeScopeSubject.Display { - header = "{{if ne .Scope \"\"}}**{{.Scope}}:** {{end}}{{.Subject}}" - } else { - header = "{{.Subject}}" - } - - body = fmt.Sprintf(`### {{.Title}} -{{range .Commits}} -* %s{{end}} -`, header) + return NewCustomTemplateBuilder() } - - return fmt.Sprintf(`{{range .CommitGroups}} -%s{{end}}`, body) -} - -func (*templateBuilderImpl) reverts() string { - return `{{if .RevertCommits}} -### Reverts -{{range .RevertCommits}} -* {{.Revert.Header}}{{end}} -{{end}}` -} - -func (t *templateBuilderImpl) merges(style string) string { - var title string - - switch style { - case styleGitHub: - title = "Pull Requests" - default: - title = "Merges" - } - - return fmt.Sprintf(`{{if .MergeCommits}} -### %s -{{range .MergeCommits}} -* {{.Header}}{{end}} -{{end}}`, title) -} - -func (*templateBuilderImpl) notes() string { - return `{{range .NoteGroups}} -### {{.Title}} -{{range .Notes}} -{{.Body}} -{{end}} -{{end}}` } diff --git a/cmd/git-chglog/variables.go b/cmd/git-chglog/variables.go index 0253f10b..bcb63803 100644 --- a/cmd/git-chglog/variables.go +++ b/cmd/git-chglog/variables.go @@ -86,9 +86,11 @@ var ( // Templates var ( - tplStandard = "standard" - tplCool = "cool" - templates = []string{ + tplKeepAChangelog = "keep-a-changelog" + tplStandard = "standard" + tplCool = "cool" + templates = []string{ + tplKeepAChangelog, tplStandard, tplCool, }