refactor: use better commands and flags name (#7)
* build: update go.mod * refactor: replace debug with verbose * refactor: split action from main * refactor: move all cli app inside pkg cli * chore(readme): use generate command Co-authored-by: Tran Hau <ngtranhau@gmail.com>main
parent
5ea13ce99f
commit
32a1b40013
|
@ -1,6 +1,9 @@
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Window
|
||||||
|
*.exe
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,10 @@ GO111module=on go get github.com/haunt98/changeloguru
|
||||||
changeloguru --help
|
changeloguru --help
|
||||||
|
|
||||||
# Generate changelog v1.0.0
|
# Generate changelog v1.0.0
|
||||||
changeloguru --version v1.0.0
|
changeloguru generate --version v1.0.0
|
||||||
|
|
||||||
# Generate changelog v2.0.0 from HEAD to tag v1.0.0
|
# Generate changelog v2.0.0 from HEAD to tag v1.0.0
|
||||||
changeloguru --to v1.0.0 --version v2.0.0
|
changeloguru generate --to v1.0.0 --version v2.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -6,15 +6,16 @@ require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/fatih/color v1.10.0
|
github.com/fatih/color v1.10.0
|
||||||
github.com/go-git/go-git/v5 v5.3.0
|
github.com/go-git/go-git/v5 v5.3.0
|
||||||
github.com/google/go-cmp v0.5.4 // indirect
|
github.com/google/go-cmp v0.5.5 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sebdah/goldie/v2 v2.5.3
|
github.com/sebdah/goldie/v2 v2.5.3
|
||||||
|
github.com/sergi/go-diff v1.2.0 // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/urfave/cli/v2 v2.3.0
|
github.com/urfave/cli/v2 v2.3.0
|
||||||
golang.org/x/mod v0.4.2
|
golang.org/x/mod v0.4.2
|
||||||
golang.org/x/net v0.0.0-20210326220855-61e056675ecf // indirect
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 // indirect
|
||||||
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
19
go.sum
19
go.sum
|
@ -32,8 +32,8 @@ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod
|
||||||
github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc=
|
github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc=
|
||||||
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
|
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
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/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
|
@ -68,8 +68,9 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||||
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
|
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
|
||||||
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||||
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
@ -94,8 +95,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||||
golang.org/x/net v0.0.0-20210326220855-61e056675ecf h1:WUcCxqQqDT0aXO4VnQbfMvp4zh7m1Gb2clVuHUAGGRE=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc=
|
||||||
golang.org/x/net v0.0.0-20210326220855-61e056675ecf/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -108,13 +109,15 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
||||||
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
241
main.go
241
main.go
|
@ -2,40 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/haunt98/changeloguru/pkg/changelog"
|
"github.com/haunt98/changeloguru/pkg/cli"
|
||||||
"github.com/haunt98/changeloguru/pkg/convention"
|
|
||||||
"github.com/haunt98/changeloguru/pkg/git"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
"golang.org/x/mod/semver"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
appName = "changeloguru"
|
|
||||||
|
|
||||||
currentDir = "."
|
|
||||||
markdownFiletype = "md"
|
|
||||||
|
|
||||||
defaultRepository = currentDir
|
|
||||||
defaultOutput = currentDir
|
|
||||||
defaultFilename = "CHANGELOG"
|
|
||||||
defaultFiletype = markdownFiletype
|
|
||||||
|
|
||||||
fromFlag = "from"
|
|
||||||
toFlag = "to"
|
|
||||||
versionFlag = "version"
|
|
||||||
scopeFlag = "scope"
|
|
||||||
repositoryFlag = "repository"
|
|
||||||
outputFlag = "output"
|
|
||||||
filenameFlag = "filename"
|
|
||||||
filetypeFlag = "filetype"
|
|
||||||
debugFlag = "debug"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -43,215 +13,10 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
a := &action{}
|
app := cli.NewApp()
|
||||||
|
|
||||||
app := &cli.App{
|
|
||||||
Name: appName,
|
|
||||||
Usage: "generate changelog from conventional commits",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: fromFlag,
|
|
||||||
Usage: "generate from `COMMIT`",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: toFlag,
|
|
||||||
Usage: "generate to `COMMIT`",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: versionFlag,
|
|
||||||
Usage: "`VERSION` to generate, follow Semantic Versioning",
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: scopeFlag,
|
|
||||||
Usage: "scope to generate",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: repositoryFlag,
|
|
||||||
Usage: "`REPOSITORY` directory path",
|
|
||||||
DefaultText: defaultRepository,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: outputFlag,
|
|
||||||
Usage: "`OUTPUT` directory path",
|
|
||||||
DefaultText: defaultOutput,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: filenameFlag,
|
|
||||||
Usage: "output `FILENAME`",
|
|
||||||
DefaultText: defaultFilename,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: filetypeFlag,
|
|
||||||
Usage: "output `FILETYPE`",
|
|
||||||
DefaultText: defaultFiletype,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: debugFlag,
|
|
||||||
Aliases: []string{"d"},
|
|
||||||
Usage: "show debugging info",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: a.Run,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
// Highlight error
|
// Highlight error
|
||||||
fmtErr.Printf("[%s error]: ", appName)
|
fmtErr.Printf("[%s error]: ", cli.AppName)
|
||||||
fmt.Printf("%s\n", err.Error())
|
fmt.Printf("%s\n", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type action struct {
|
|
||||||
flags struct {
|
|
||||||
debug bool
|
|
||||||
from string
|
|
||||||
to string
|
|
||||||
version string
|
|
||||||
scopes map[string]struct{}
|
|
||||||
repository string
|
|
||||||
output string
|
|
||||||
filename string
|
|
||||||
filetype string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) Run(c *cli.Context) error {
|
|
||||||
// Show help if there is nothing
|
|
||||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
|
||||||
return cli.ShowAppHelp(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.getFlags(c)
|
|
||||||
|
|
||||||
commits, err := a.getCommits()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
conventionalCommits := a.getConventionalCommits(commits)
|
|
||||||
|
|
||||||
if err := a.generateChangelog(conventionalCommits); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) getFlags(c *cli.Context) {
|
|
||||||
a.flags.debug = c.Bool(debugFlag)
|
|
||||||
a.flags.from = c.String(fromFlag)
|
|
||||||
a.flags.to = c.String(toFlag)
|
|
||||||
a.flags.version = c.String(versionFlag)
|
|
||||||
|
|
||||||
a.flags.scopes = make(map[string]struct{})
|
|
||||||
for _, scope := range c.StringSlice(scopeFlag) {
|
|
||||||
a.flags.scopes[scope] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.flags.repository = a.getFlagValue(c, repositoryFlag, defaultRepository)
|
|
||||||
a.flags.output = a.getFlagValue(c, outputFlag, defaultOutput)
|
|
||||||
a.flags.filename = a.getFlagValue(c, filenameFlag, defaultFilename)
|
|
||||||
a.flags.filetype = a.getFlagValue(c, filetypeFlag, defaultFiletype)
|
|
||||||
|
|
||||||
if a.flags.debug {
|
|
||||||
a.logDebug("flags %+v", a.flags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) getFlagValue(c *cli.Context, flag, fallback string) string {
|
|
||||||
value := c.String(flag)
|
|
||||||
if value == "" {
|
|
||||||
value = fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) getCommits() ([]git.Commit, error) {
|
|
||||||
r, err := git.NewRepository(a.flags.repository)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.Log(a.flags.from, a.flags.to)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) getConventionalCommits(commits []git.Commit) []convention.Commit {
|
|
||||||
conventionalCommits := make([]convention.Commit, 0, len(commits))
|
|
||||||
for _, commit := range commits {
|
|
||||||
conventionalCommit, err := convention.NewCommit(commit)
|
|
||||||
if err != nil {
|
|
||||||
a.logDebug("failed to new conventional commits %+v: %s", commit, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
conventionalCommits = append(conventionalCommits, conventionalCommit)
|
|
||||||
}
|
|
||||||
|
|
||||||
return conventionalCommits
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) generateChangelog(commits []convention.Commit) error {
|
|
||||||
realOutput := a.getRealOutput()
|
|
||||||
|
|
||||||
version, err := a.getVersion()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch a.flags.filetype {
|
|
||||||
case markdownFiletype:
|
|
||||||
return a.generateMarkdownChangelog(realOutput, version, commits)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown filetype %s", a.flags.filetype)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) getRealOutput() string {
|
|
||||||
nameWithExt := a.flags.filename + "." + a.flags.filetype
|
|
||||||
realOutput := filepath.Join(a.flags.output, nameWithExt)
|
|
||||||
|
|
||||||
return realOutput
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) getVersion() (string, error) {
|
|
||||||
if a.flags.version == "" {
|
|
||||||
return "", fmt.Errorf("empty version")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(a.flags.version, "v") {
|
|
||||||
a.flags.version = "v" + a.flags.version
|
|
||||||
}
|
|
||||||
|
|
||||||
if !semver.IsValid(a.flags.version) {
|
|
||||||
return "", fmt.Errorf("invalid semver %s", a.flags.version)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.logDebug("version %s", a.flags.version)
|
|
||||||
|
|
||||||
return a.flags.version, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) generateMarkdownChangelog(output, version string, commits []convention.Commit) error {
|
|
||||||
// If CHANGELOG file already exist
|
|
||||||
var oldData string
|
|
||||||
bytes, err := os.ReadFile(output)
|
|
||||||
if err == nil {
|
|
||||||
oldData = string(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
markdownGenerator := changelog.NewMarkdownGenerator(oldData, version, time.Now())
|
|
||||||
newData := markdownGenerator.Generate(commits, a.flags.scopes)
|
|
||||||
|
|
||||||
if err := os.WriteFile(output, []byte(newData), 0o644); err != nil {
|
|
||||||
return fmt.Errorf("failed to write file %s: %w", output, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *action) logDebug(format string, v ...interface{}) {
|
|
||||||
if a.flags.debug {
|
|
||||||
log.Printf(format, v...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
currentDir = "."
|
||||||
|
markdownFiletype = "md"
|
||||||
|
|
||||||
|
defaultRepository = currentDir
|
||||||
|
defaultOutput = currentDir
|
||||||
|
defaultFilename = "CHANGELOG"
|
||||||
|
defaultFiletype = markdownFiletype
|
||||||
|
)
|
||||||
|
|
||||||
|
type action struct {
|
||||||
|
flags struct {
|
||||||
|
verbose bool
|
||||||
|
from string
|
||||||
|
to string
|
||||||
|
version string
|
||||||
|
scopes map[string]struct{}
|
||||||
|
repository string
|
||||||
|
output string
|
||||||
|
filename string
|
||||||
|
filetype string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) RunHelp(c *cli.Context) error {
|
||||||
|
return cli.ShowAppHelp(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) getFlags(c *cli.Context) {
|
||||||
|
a.flags.verbose = c.Bool(verboseFlag)
|
||||||
|
a.flags.from = c.String(fromFlag)
|
||||||
|
a.flags.to = c.String(toFlag)
|
||||||
|
a.flags.version = c.String(versionFlag)
|
||||||
|
|
||||||
|
a.flags.scopes = make(map[string]struct{})
|
||||||
|
for _, scope := range c.StringSlice(scopeFlag) {
|
||||||
|
a.flags.scopes[scope] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.flags.repository = a.getFlagValue(c, repositoryFlag, defaultRepository)
|
||||||
|
a.flags.output = a.getFlagValue(c, outputFlag, defaultOutput)
|
||||||
|
a.flags.filename = a.getFlagValue(c, filenameFlag, defaultFilename)
|
||||||
|
a.flags.filetype = a.getFlagValue(c, filetypeFlag, defaultFiletype)
|
||||||
|
|
||||||
|
if a.flags.verbose {
|
||||||
|
a.log("flags %+v", a.flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) getFlagValue(c *cli.Context, flag, fallback string) string {
|
||||||
|
value := c.String(flag)
|
||||||
|
if value == "" {
|
||||||
|
value = fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) log(format string, v ...interface{}) {
|
||||||
|
if a.flags.verbose {
|
||||||
|
log.Printf(format, v...)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/haunt98/changeloguru/pkg/changelog"
|
||||||
|
"github.com/haunt98/changeloguru/pkg/convention"
|
||||||
|
"github.com/haunt98/changeloguru/pkg/git"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *action) RunGenerate(c *cli.Context) error {
|
||||||
|
// Show help if there is nothing
|
||||||
|
if c.NumFlags() == 0 {
|
||||||
|
return cli.ShowAppHelp(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.getFlags(c)
|
||||||
|
|
||||||
|
commits, err := a.getCommits()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
conventionalCommits := a.getConventionalCommits(commits)
|
||||||
|
|
||||||
|
if err := a.generateChangelog(conventionalCommits); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) getCommits() ([]git.Commit, error) {
|
||||||
|
r, err := git.NewRepository(a.flags.repository)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Log(a.flags.from, a.flags.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) getConventionalCommits(commits []git.Commit) []convention.Commit {
|
||||||
|
conventionalCommits := make([]convention.Commit, 0, len(commits))
|
||||||
|
for _, commit := range commits {
|
||||||
|
conventionalCommit, err := convention.NewCommit(commit)
|
||||||
|
if err != nil {
|
||||||
|
a.log("failed to new conventional commits %+v: %s", commit, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
conventionalCommits = append(conventionalCommits, conventionalCommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conventionalCommits
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) generateChangelog(commits []convention.Commit) error {
|
||||||
|
realOutput := a.getRealOutput()
|
||||||
|
|
||||||
|
version, err := a.getVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch a.flags.filetype {
|
||||||
|
case markdownFiletype:
|
||||||
|
return a.generateMarkdownChangelog(realOutput, version, commits)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown filetype %s", a.flags.filetype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) getRealOutput() string {
|
||||||
|
nameWithExt := a.flags.filename + "." + a.flags.filetype
|
||||||
|
realOutput := filepath.Join(a.flags.output, nameWithExt)
|
||||||
|
|
||||||
|
return realOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) getVersion() (string, error) {
|
||||||
|
if a.flags.version == "" {
|
||||||
|
return "", fmt.Errorf("empty version")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(a.flags.version, "v") {
|
||||||
|
a.flags.version = "v" + a.flags.version
|
||||||
|
}
|
||||||
|
|
||||||
|
if !semver.IsValid(a.flags.version) {
|
||||||
|
return "", fmt.Errorf("invalid semver %s", a.flags.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.log("version %s", a.flags.version)
|
||||||
|
|
||||||
|
return a.flags.version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *action) generateMarkdownChangelog(output, version string, commits []convention.Commit) error {
|
||||||
|
// If CHANGELOG file already exist
|
||||||
|
var oldData string
|
||||||
|
bytes, err := os.ReadFile(output)
|
||||||
|
if err == nil {
|
||||||
|
oldData = string(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
markdownGenerator := changelog.NewMarkdownGenerator(oldData, version, time.Now())
|
||||||
|
newData := markdownGenerator.Generate(commits, a.flags.scopes)
|
||||||
|
|
||||||
|
if err := os.WriteFile(output, []byte(newData), 0o644); err != nil {
|
||||||
|
return fmt.Errorf("failed to write file %s: %w", output, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
const (
|
||||||
|
AppName = "changeloguru"
|
||||||
|
|
||||||
|
// flags
|
||||||
|
fromFlag = "from"
|
||||||
|
toFlag = "to"
|
||||||
|
versionFlag = "version"
|
||||||
|
scopeFlag = "scope"
|
||||||
|
repositoryFlag = "repository"
|
||||||
|
outputFlag = "output"
|
||||||
|
filenameFlag = "filename"
|
||||||
|
filetypeFlag = "filetype"
|
||||||
|
verboseFlag = "verbose"
|
||||||
|
|
||||||
|
// commands
|
||||||
|
generateCommand = "generate"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// flags
|
||||||
|
verboseAliases = []string{"v"}
|
||||||
|
|
||||||
|
// commands
|
||||||
|
generateAliases = []string{"gen"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewApp() *cli.App {
|
||||||
|
a := &action{}
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Name: AppName,
|
||||||
|
Usage: "generate changelog from conventional commits",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: verboseFlag,
|
||||||
|
Aliases: verboseAliases,
|
||||||
|
Usage: "show what is going on",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: generateCommand,
|
||||||
|
Aliases: generateAliases,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: fromFlag,
|
||||||
|
Usage: "generate from `COMMIT`",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: toFlag,
|
||||||
|
Usage: "generate to `COMMIT`",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: versionFlag,
|
||||||
|
Usage: "`VERSION` to generate, follow Semantic Versioning",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: scopeFlag,
|
||||||
|
Usage: "scope to generate",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: repositoryFlag,
|
||||||
|
Usage: "`REPOSITORY` directory path",
|
||||||
|
DefaultText: defaultRepository,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: outputFlag,
|
||||||
|
Usage: "`OUTPUT` directory path",
|
||||||
|
DefaultText: defaultOutput,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: filenameFlag,
|
||||||
|
Usage: "output `FILENAME`",
|
||||||
|
DefaultText: defaultFilename,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: filetypeFlag,
|
||||||
|
Usage: "output `FILETYPE`",
|
||||||
|
DefaultText: defaultFiletype,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: a.RunGenerate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: a.RunHelp,
|
||||||
|
}
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
Loading…
Reference in New Issue