mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-23 10:25:24 +00:00
feat: Add --tag-filter-pattern flag.
This flag specifies a regular expression and only matched tags will be included in change log. Closes #43
This commit is contained in:
parent
63a4e63702
commit
1198e283de
10 changed files with 222 additions and 65 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -10,6 +10,7 @@
|
|||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
git-chglog
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
|
@ -31,6 +32,10 @@ Icon
|
|||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Intellij IDEA
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
|
|
|
|||
30
README.md
30
README.md
|
|
@ -166,15 +166,16 @@ USAGE:
|
|||
4. <name> - Commit contained in <name>.
|
||||
|
||||
OPTIONS:
|
||||
--init generate the git-chglog configuration file in interactive
|
||||
--config value, -c value specifies a different configuration file to pick up (default: ".chglog/config.yml")
|
||||
--output value, -o value output path and filename for the changelogs. If not specified, output to stdout
|
||||
--next-tag value treat unreleased commits as specified tags (EXPERIMENTAL)
|
||||
--silent disable stdout output
|
||||
--no-color disable color output [$NO_COLOR]
|
||||
--no-emoji disable emoji output [$NO_EMOJI]
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
--init generate the git-chglog configuration file in interactive
|
||||
--config value, -c value specifies a different configuration file to pick up (default: ".chglog/config.yml")
|
||||
--output value, -o value output path and filename for the changelogs. If not specified, output to stdout
|
||||
--next-tag value treat unreleased commits as specified tags (EXPERIMENTAL)
|
||||
--silent disable stdout output
|
||||
--no-color disable color output [$NO_COLOR]
|
||||
--no-emoji disable emoji output [$NO_EMOJI]
|
||||
--tag-filter-pattern value, -p value regular expression of tag filter. Is specified, only matched tags will be picked
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
|
|
@ -512,7 +513,16 @@ See godoc [RenderData][doc-render-data] for available variables.
|
|||
This is a step that is necessary for project operation in many cases.
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Can I generated CHANGELOG based on certain tags?</summary>
|
||||
|
||||
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'
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## TODO
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
type Options struct {
|
||||
Processor Processor
|
||||
NextTag string // Treat unreleased commits as specified tags (EXPERIMENTAL)
|
||||
TagFilterPattern string // Filter tag by regexp
|
||||
CommitFilters map[string][]string // Filter by using `Commit` properties and values. Filtering is not done by specifying an empty value
|
||||
CommitSortBy string // Property name to use for sorting `Commit` (e.g. `Scope`)
|
||||
CommitGroupBy string // Property name of `Commit` to be grouped into `CommitGroup` (e.g. `Type`)
|
||||
|
|
@ -108,7 +109,7 @@ func NewGenerator(config *Config) *Generator {
|
|||
return &Generator{
|
||||
client: client,
|
||||
config: config,
|
||||
tagReader: newTagReader(client),
|
||||
tagReader: newTagReader(client, config.Options.TagFilterPattern),
|
||||
tagSelector: newTagSelector(),
|
||||
commitParser: newCommitParser(client, config),
|
||||
commitExtractor: newCommitExtractor(config.Options),
|
||||
|
|
|
|||
|
|
@ -391,3 +391,64 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
|||
[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`, strings.TrimSpace(buf.String()))
|
||||
}
|
||||
|
||||
func TestGeneratorWithTagFiler(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testName := "type_scope_subject"
|
||||
|
||||
setup(testName, func(commit commitFunc, tag tagFunc, _ gitcmd.Client) {
|
||||
commit("2018-01-01 00:00:00", "feat(core): version dev-1.0.0", "")
|
||||
tag("dev-1.0.0")
|
||||
|
||||
commit("2018-02-01 00:00:00", "feat(core): version v1.0.0", "")
|
||||
tag("v1.0.0")
|
||||
})
|
||||
|
||||
gen := NewGenerator(&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{
|
||||
TagFilterPattern: "^v",
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"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, "")
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(`<a name="unreleased"></a>
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
<a name="v1.0.0"></a>
|
||||
## v1.0.0 - 2018-02-01
|
||||
### Features
|
||||
- **core:** version v1.0.0
|
||||
- **core:** version dev-1.0.0
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/git-chglog/git-chglog/compare/v1.0.0...HEAD`, strings.TrimSpace(buf.String()))
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
|||
},
|
||||
Options: &chglog.Options{
|
||||
NextTag: ctx.NextTag,
|
||||
TagFilterPattern: ctx.TagFilterPattern,
|
||||
CommitFilters: opts.Commits.Filters,
|
||||
CommitSortBy: opts.Commits.SortBy,
|
||||
CommitGroupBy: opts.CommitGroups.GroupBy,
|
||||
|
|
|
|||
|
|
@ -6,16 +6,17 @@ import (
|
|||
|
||||
// CLIContext ...
|
||||
type CLIContext struct {
|
||||
WorkingDir string
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
ConfigPath string
|
||||
OutputPath string
|
||||
Silent bool
|
||||
NoColor bool
|
||||
NoEmoji bool
|
||||
Query string
|
||||
NextTag string
|
||||
WorkingDir string
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
ConfigPath string
|
||||
OutputPath string
|
||||
Silent bool
|
||||
NoColor bool
|
||||
NoEmoji bool
|
||||
Query string
|
||||
NextTag string
|
||||
TagFilterPattern string
|
||||
}
|
||||
|
||||
// InitContext ...
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||
ttl := color.New(color.FgYellow).SprintFunc()
|
||||
|
||||
cli.AppHelpTemplate = fmt.Sprintf(`
|
||||
|
|
@ -114,63 +114,77 @@ func main() {
|
|||
EnvVar: "NO_EMOJI",
|
||||
},
|
||||
|
||||
// tag-filter-pattern
|
||||
cli.StringFlag{
|
||||
Name: "tag-filter-pattern, p",
|
||||
Usage: "Regular expression of tag filter. Is specified, only matched tags will be picked",
|
||||
},
|
||||
|
||||
// help & version
|
||||
cli.HelpFlag,
|
||||
cli.VersionFlag,
|
||||
}
|
||||
|
||||
app.Action = func(c *cli.Context) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to get working directory", err)
|
||||
os.Exit(ExitCodeError)
|
||||
}
|
||||
app.Action = actionFunc
|
||||
|
||||
// initializer
|
||||
if c.Bool("init") {
|
||||
initializer := NewInitializer(
|
||||
&InitContext{
|
||||
WorkingDir: wd,
|
||||
Stdout: colorable.NewColorableStdout(),
|
||||
Stderr: colorable.NewColorableStderr(),
|
||||
},
|
||||
fs,
|
||||
NewQuestioner(
|
||||
gitcmd.New(&gitcmd.Config{
|
||||
Bin: "git",
|
||||
}),
|
||||
fs,
|
||||
),
|
||||
NewConfigBuilder(),
|
||||
templateBuilderFactory,
|
||||
)
|
||||
return app
|
||||
}
|
||||
|
||||
os.Exit(initializer.Run())
|
||||
}
|
||||
func AppAction(c *cli.Context) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to get working directory", err)
|
||||
os.Exit(ExitCodeError)
|
||||
}
|
||||
|
||||
// chglog
|
||||
chglogCLI := NewCLI(
|
||||
&CLIContext{
|
||||
// initializer
|
||||
if c.Bool("init") {
|
||||
initializer := NewInitializer(
|
||||
&InitContext{
|
||||
WorkingDir: wd,
|
||||
Stdout: colorable.NewColorableStdout(),
|
||||
Stderr: colorable.NewColorableStderr(),
|
||||
ConfigPath: c.String("config"),
|
||||
OutputPath: c.String("output"),
|
||||
Silent: c.Bool("silent"),
|
||||
NoColor: c.Bool("no-color"),
|
||||
NoEmoji: c.Bool("no-emoji"),
|
||||
Query: c.Args().First(),
|
||||
NextTag: c.String("next-tag"),
|
||||
},
|
||||
fs,
|
||||
NewConfigLoader(),
|
||||
NewGenerator(),
|
||||
NewQuestioner(
|
||||
gitcmd.New(&gitcmd.Config{
|
||||
Bin: "git",
|
||||
}),
|
||||
fs,
|
||||
),
|
||||
NewConfigBuilder(),
|
||||
templateBuilderFactory,
|
||||
)
|
||||
|
||||
os.Exit(chglogCLI.Run())
|
||||
|
||||
return nil
|
||||
os.Exit(initializer.Run())
|
||||
}
|
||||
|
||||
// chglog
|
||||
chglogCLI := NewCLI(
|
||||
&CLIContext{
|
||||
WorkingDir: wd,
|
||||
Stdout: colorable.NewColorableStdout(),
|
||||
Stderr: colorable.NewColorableStderr(),
|
||||
ConfigPath: c.String("config"),
|
||||
OutputPath: c.String("output"),
|
||||
Silent: c.Bool("silent"),
|
||||
NoColor: c.Bool("no-color"),
|
||||
NoEmoji: c.Bool("no-emoji"),
|
||||
Query: c.Args().First(),
|
||||
NextTag: c.String("next-tag"),
|
||||
TagFilterPattern: c.String("tag-filter-pattern"),
|
||||
},
|
||||
fs,
|
||||
NewConfigLoader(),
|
||||
NewGenerator(),
|
||||
)
|
||||
|
||||
os.Exit(chglogCLI.Run())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := CreateApp(AppAction)
|
||||
app.Run(os.Args)
|
||||
}
|
||||
|
|
|
|||
40
cmd/git-chglog/main_test.go
Normal file
40
cmd/git-chglog/main_test.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var gAssert *assert.Assertions
|
||||
|
||||
func mock_app_action(c *cli.Context) error {
|
||||
assert := gAssert
|
||||
assert.Equal("c.yml", c.String("config"))
|
||||
assert.Equal("^v", c.String("tag-filter-pattern"))
|
||||
assert.Equal("o.md", c.String("output"))
|
||||
assert.Equal("v5", c.String("next-tag"))
|
||||
assert.True(c.Bool("silent"))
|
||||
assert.True(c.Bool("no-color"))
|
||||
assert.True(c.Bool("no-emoji"))
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestCreateApp(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
assert.True(true)
|
||||
gAssert = assert
|
||||
|
||||
app := CreateApp(mock_app_action)
|
||||
args := []string {
|
||||
"git-chglog",
|
||||
"--silent",
|
||||
"--no-color",
|
||||
"--no-emoji",
|
||||
"--config", "c.yml",
|
||||
"--output", "o.md",
|
||||
"--next-tag", "v5",
|
||||
"--tag-filter-pattern", "^v",
|
||||
}
|
||||
app.Run(args)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package chglog
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -13,12 +14,14 @@ type tagReader struct {
|
|||
client gitcmd.Client
|
||||
format string
|
||||
separator string
|
||||
reFilter *regexp.Regexp
|
||||
}
|
||||
|
||||
func newTagReader(client gitcmd.Client) *tagReader {
|
||||
func newTagReader(client gitcmd.Client, filterPattern string) *tagReader {
|
||||
return &tagReader{
|
||||
client: client,
|
||||
separator: "@@__CHGLOG__@@",
|
||||
reFilter: regexp.MustCompile(filterPattern),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +59,12 @@ func (r *tagReader) ReadAll() ([]*Tag, error) {
|
|||
date = t
|
||||
}
|
||||
|
||||
if r.reFilter != nil {
|
||||
if !r.reFilter.MatchString(name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
tags = append(tags, &Tag{
|
||||
Name: name,
|
||||
Subject: subject,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ func TestTagReader(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
actual, err := newTagReader(client).ReadAll()
|
||||
actual, err := newTagReader(client, "").ReadAll()
|
||||
assert.Nil(err)
|
||||
|
||||
assert.Equal(
|
||||
|
|
@ -103,4 +103,19 @@ func TestTagReader(t *testing.T) {
|
|||
},
|
||||
actual,
|
||||
)
|
||||
|
||||
actual_filtered, err_filtered := newTagReader(client, "^v").ReadAll()
|
||||
assert.Nil(err_filtered)
|
||||
assert.Equal(
|
||||
[]*Tag{
|
||||
&Tag{
|
||||
Name: "v2.0.4-beta.1",
|
||||
Subject: "Release v2.0.4-beta.1",
|
||||
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
Next: nil,
|
||||
Previous: nil,
|
||||
},
|
||||
},
|
||||
actual_filtered,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue