From 4f3fdc4dae556dba128de4e3cb9af057da9c2d25 Mon Sep 17 00:00:00 2001 From: Trent Albright Date: Sun, 28 Mar 2021 23:18:36 -0400 Subject: [PATCH] feat: add sprig template functions support (#131) * cherry-pick from delmendo * add tests, docs, and lift hermetic restriction * remove duplicate funcs that are now provided by sprig * switch func load order to allow built-ins precedence * Update chglog.go Co-authored-by: Dirk Elmendorf --- README.md | 23 ++++++------ chglog.go | 15 ++------ chglog_test.go | 82 +++++++++++++++++++++++++++++++++++++++++- go.mod | 1 + go.sum | 25 ++++++++++++- testdata/with_sprig.md | 57 +++++++++++++++++++++++++++++ 6 files changed, 176 insertions(+), 27 deletions(-) create mode 100644 testdata/with_sprig.md diff --git a/README.md b/README.md index 17bbb9c9..fa6cab54 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Coverage Status](https://img.shields.io/coveralls/github/git-chglog/git-chglog.svg?style=flat-square)](https://coveralls.io/github/git-chglog/git-chglog?branch=master) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/git-chglog/git-chglog/blob/master/LICENSE) -> CHANGELOG generator implemented in Go (Golang). +> CHANGELOG generator implemented in Go (Golang). > _Anytime, anywhere, Write your CHANGELOG._ ## Table of Contents @@ -130,7 +130,7 @@ $ git-chglog --version ### Quick Start -`git-chglog` requires configuration files and templates to generate a CHANGELOG. +`git-chglog` requires configuration files and templates to generate a CHANGELOG. However, it is a waste of time to create configuration files and templates from scratch. @@ -146,7 +146,7 @@ git-chglog --init You are now ready for configuration files and templates! -Let's immediately generate a CHANGELOG of your project. +Let's immediately generate a CHANGELOG of your project. By doing the following simple command, Markdown for your CHANGELOG is displayed on stdout. @@ -430,8 +430,7 @@ Options to detect notes contained in commit bodies. ## Templates -The `git-chglog` template uses the `text/template` package. For basic usage please -refer to the following. +The `git-chglog` template uses the `text/template` package and enhanced templating functions provided by [Sprig](http://masterminds.github.io/sprig). For basic usage please refer to the following. > [text/template](https://golang.org/pkg/text/template/) @@ -607,7 +606,7 @@ Within a `Commit`, the following Jira data can be used in template: It is ideal to describe everything included in CHANGELOG in your commits. But actually it is very difficult to do it perfectly. - There are times when you need to edit the generated output to write a great CHANGELOG. + There are times when you need to edit the generated output to write a great CHANGELOG. By displaying it on the standard output, it makes it easy to change the contents. @@ -617,7 +616,7 @@ Within a `Commit`, the following Jira data can be used in template: Yes, it can be solved by using the `--next-tag` flag. - For example, let's say you want to upgrade your project to `2.0.0`. + For example, let's say you want to upgrade your project to `2.0.0`. You can create CHANGELOG containing `2.0.0` as follows. ```bash @@ -634,11 +633,11 @@ Within a `Commit`, the following Jira data can be used in template:
Can I generate a CHANGELOG based on certain tags? - + Yes, it can be solved by use the `--tag-filter-pattern` flag. - + For example, the following command will only include tags starting with "v": - + ```bash git-chglog --tag-filter-pattern '^v' ``` @@ -676,10 +675,10 @@ Bugs, feature requests and comments are more than welcome in the [issues]. ### Feedback -I would like to make `git-chglog` a better tool. +I would like to make `git-chglog` a better tool. The goal is to be able to use in various projects. -Therefore, your feedback is very useful. +Therefore, your feedback is very useful. I am very happy to tell you your opinions on Issues and PR :heart: ## CHANGELOG diff --git a/chglog.go b/chglog.go index 76a8fbec..541f577a 100644 --- a/chglog.go +++ b/chglog.go @@ -12,6 +12,7 @@ import ( "text/template" "time" + "github.com/Masterminds/sprig/v3" "github.com/tsuyoshiwada/go-gitcmd" ) @@ -324,18 +325,6 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve "datetime": func(layout string, input time.Time) string { return input.Format(layout) }, - // check whether substr is within s - "contains": strings.Contains, - // check whether s begins with prefix - "hasPrefix": strings.HasPrefix, - // check whether s ends with suffix - "hasSuffix": strings.HasSuffix, - // replace the first n instances of old with new - "replace": strings.Replace, - // lower case a string - "lower": strings.ToLower, - // upper case a string - "upper": strings.ToUpper, // upper case the first character of a string "upperFirst": func(s string) string { if len(s) > 0 { @@ -355,7 +344,7 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve fname := filepath.Base(gen.config.Template) - t := template.Must(template.New(fname).Funcs(fmap).ParseFiles(gen.config.Template)) + t := template.Must(template.New(fname).Funcs(sprig.TxtFuncMap()).Funcs(fmap).ParseFiles(gen.config.Template)) return t.Execute(w, &RenderData{ Info: gen.config.Info, diff --git a/chglog_test.go b/chglog_test.go index 969ee3b7..a00359bb 100644 --- a/chglog_test.go +++ b/chglog_test.go @@ -471,7 +471,7 @@ func TestGeneratorWithTagFiler(t *testing.T) { } -func TestGeneratorWithTimmedBody(t *testing.T) { +func TestGeneratorWithTrimmedBody(t *testing.T) { assert := assert.New(t) testName := "trimmed_body" @@ -549,3 +549,83 @@ When using .TrimmedBody Notes are not included and can only appear in the Notes [Unreleased]: https://github.com/git-chglog/git-chglog/compare/1.0.0...HEAD`, expected) } + +func TestGeneratorWithSprig(t *testing.T) { + assert := assert.New(t) + testName := "with_sprig" + + setup(testName, func(commit commitFunc, tag tagFunc, _ gitcmd.Client) { + commit("2018-01-01 00:00:00", "feat(core): version 1.0.0", "") + tag("1.0.0") + + commit("2018-02-01 00:00:00", "feat(core): version 2.0.0", "") + tag("2.0.0") + + commit("2018-03-01 00:00:00", "feat(core): version 3.0.0", "") + }) + + gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true), + &Config{ + Bin: "git", + WorkingDir: filepath.Join(testRepoRoot, testName), + Template: filepath.Join(cwd, "testdata", testName+".md"), + Info: &Info{ + Title: "CHANGELOG Example", + RepositoryURL: "https://github.com/git-chglog/git-chglog", + }, + Options: &Options{ + Sort: "date", + NextTag: "3.0.0", + CommitFilters: map[string][]string{ + "Type": { + "feat", + }, + }, + CommitSortBy: "Scope", + CommitGroupBy: "Type", + CommitGroupSortBy: "Title", + CommitGroupTitleMaps: map[string]string{ + "feat": "Features", + }, + HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$", + HeaderPatternMaps: []string{ + "Type", + "Scope", + "Subject", + }, + }, + }) + + buf := &bytes.Buffer{} + err := gen.Generate(buf, "") + expected := strings.TrimSpace(buf.String()) + + assert.Nil(err) + assert.Equal(`My Changelog + +## [Unreleased] + + + +## [3.0.0] - 2018-03-01 +### Features +- **CORE:** version 3.0.0 + + + +## [2.0.0] - 2018-02-01 +### Features +- **CORE:** version 2.0.0 + + + +## 1.0.0 - 2018-01-01 +### Features +- **CORE:** version 1.0.0 + + +[Unreleased]: https://github.com/git-chglog/git-chglog/compare/3.0.0...HEAD +[3.0.0]: https://github.com/git-chglog/git-chglog/compare/2.0.0...3.0.0 +[2.0.0]: https://github.com/git-chglog/git-chglog/compare/1.0.0...2.0.0`, expected) + +} diff --git a/go.mod b/go.mod index c56b0ef7..6eddc45c 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/AlecAivazis/survey/v2 v2.2.9 + github.com/Masterminds/sprig/v3 v3.2.2 github.com/andygrunwald/go-jira v1.13.0 github.com/coreos/go-semver v0.3.0 github.com/fatih/color v1.10.0 diff --git a/go.sum b/go.sum index c6593849..aa19b196 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,12 @@ github.com/AlecAivazis/survey/v2 v2.2.9 h1:LWvJtUswz/W9/zVVXELrmlvdwWcKE60ZAw0FWV9vssk= github.com/AlecAivazis/survey/v2 v2.2.9/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/andygrunwald/go-jira v1.13.0 h1:vvIImGgX32bHfoiyUwkNo+/YrPnRczNarvhLOncP6dE= @@ -22,8 +28,13 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -40,16 +51,26 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ= @@ -60,8 +81,9 @@ github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -74,6 +96,7 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/testdata/with_sprig.md b/testdata/with_sprig.md new file mode 100644 index 00000000..e4426012 --- /dev/null +++ b/testdata/with_sprig.md @@ -0,0 +1,57 @@ +{{ title "my changelog" }} +{{ if .Versions -}} + +## [Unreleased] + +{{ if .Unreleased.CommitGroups -}} +{{ range .Unreleased.CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} +{{ end -}} +{{ 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 | upper }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .RevertCommits -}} +### Reverts +{{ range .RevertCommits -}} +- {{ .Revert.Header }} +{{ end }} +{{ end -}} + +{{- if .MergeCommits -}} +### Pull Requests +{{ range .MergeCommits -}} +- {{ .Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ 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 -}}