mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-23 02:15:12 +00:00
feat: add Jira integration (#52)
This commit is contained in:
parent
8713d96856
commit
a1c84d7a0d
22 changed files with 742 additions and 331 deletions
2
Makefile
2
Makefile
|
|
@ -7,7 +7,7 @@ clean:
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
go build -i -o git-chglog ./cmd/git-chglog
|
go build -o git-chglog ./cmd/git-chglog
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
|
|
|
||||||
83
README.md
83
README.md
|
|
@ -44,6 +44,7 @@
|
||||||
- [`options.notes`](#optionsnotes)
|
- [`options.notes`](#optionsnotes)
|
||||||
- [Templates](#templates)
|
- [Templates](#templates)
|
||||||
- [Supported Styles](#supported-styles)
|
- [Supported Styles](#supported-styles)
|
||||||
|
- [Jira Integration](#jira-integration)
|
||||||
- [FAQ](#faq)
|
- [FAQ](#faq)
|
||||||
- [TODO](#todo)
|
- [TODO](#todo)
|
||||||
- [Thanks](#thanks)
|
- [Thanks](#thanks)
|
||||||
|
|
@ -486,6 +487,88 @@ See the godoc [RenderData][doc-render-data] documentation for available variable
|
||||||
|
|
||||||
> :memo: Even with styles that are not yet supported, it is possible to make ordinary CHANGELOG.
|
> :memo: Even with styles that are not yet supported, it is possible to make ordinary CHANGELOG.
|
||||||
|
|
||||||
|
|
||||||
|
## Jira Integration
|
||||||
|
|
||||||
|
|
||||||
|
Jira is a popular project management tool. When a project uses Jira to track feature development and bug fixes,
|
||||||
|
it may also want to generate change log based information stored in Jira. With embedding a Jira story id in git
|
||||||
|
commit header, the git-chglog tool may automatically fetch data of the story from Jira, those data then can be
|
||||||
|
used to render the template.
|
||||||
|
|
||||||
|
Take the following steps to add Jira integration:
|
||||||
|
|
||||||
|
#### 1. Change the header parse pattern to recognize Jira issue id in the configure file.
|
||||||
|
|
||||||
|
__Where Jira issue is identical Jira story.__
|
||||||
|
|
||||||
|
The following is a sample pattern:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
header:
|
||||||
|
pattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$"
|
||||||
|
pattern_maps:
|
||||||
|
- Type
|
||||||
|
- JiraIssueId
|
||||||
|
- Subject
|
||||||
|
```
|
||||||
|
|
||||||
|
This sample pattern can match both forms of commit headers:
|
||||||
|
|
||||||
|
* `feat: new feature of something`
|
||||||
|
* `[JIRA-ID]: something`
|
||||||
|
|
||||||
|
#### 2. Add Jira configuration to the configure file.
|
||||||
|
|
||||||
|
The following is a sample:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jira:
|
||||||
|
info:
|
||||||
|
username: u
|
||||||
|
token: p
|
||||||
|
url: https://jira.com
|
||||||
|
issue:
|
||||||
|
type_maps:
|
||||||
|
Task: fix
|
||||||
|
Story: feat
|
||||||
|
description_pattern: "<changelog>(.*)</changelog>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Here you need to define Jira URL, access username and token (password). If you don't want to
|
||||||
|
write your Jira access credential in configure file, you may define them with environment variables:
|
||||||
|
`JIRA_URL`, `JIRA_USERNAME` and `JIRA_TOKEN`.
|
||||||
|
|
||||||
|
You also needs to define a issue type map. In above sample, Jira issue type `Task` will be
|
||||||
|
mapped to `fix` and `Story` will be mapped to `feat`.
|
||||||
|
|
||||||
|
As a Jira story's description could be very long, you might not want to include the entire
|
||||||
|
description into change log. In that case, you may define `description_pattern` like above,
|
||||||
|
so that only content embraced with `<changelog> ... </changelog>` will be included.
|
||||||
|
|
||||||
|
#### 3. Update the template to show Jira data.
|
||||||
|
|
||||||
|
In the template, if a commit contains a Jira issue id, then you may show Jira data. For example:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{{ range .CommitGroups -}}
|
||||||
|
### {{ .Title }}
|
||||||
|
{{ range .Commits -}}
|
||||||
|
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
||||||
|
{{ if .JiraIssue }} {{ .JiraIssue.Description }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end -}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Within a `Commit`, the following Jira data can be used in template:
|
||||||
|
|
||||||
|
* `.JiraIssue.Summary` - Summary of the Jira story
|
||||||
|
* `.JiraIssue.Description` - Description of the Jira story
|
||||||
|
* `.JiraIssue.Type` - Original type of the Jira story, and `.Type` will be mapped type.
|
||||||
|
* `.JiraIssue.Labels` - A list of strings, each is a Jira label.
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
|
||||||
49
chglog.go
49
chglog.go
|
|
@ -16,25 +16,30 @@ import (
|
||||||
|
|
||||||
// Options is an option used to process commits
|
// Options is an option used to process commits
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Processor Processor
|
Processor Processor
|
||||||
NextTag string // Treat unreleased commits as specified tags (EXPERIMENTAL)
|
NextTag string // Treat unreleased commits as specified tags (EXPERIMENTAL)
|
||||||
TagFilterPattern string // Filter tag by regexp
|
TagFilterPattern string // Filter tag by regexp
|
||||||
NoCaseSensitive bool // Filter commits in a case insensitive way
|
NoCaseSensitive bool // Filter commits in a case insensitive way
|
||||||
CommitFilters map[string][]string // Filter by using `Commit` properties and values. Filtering is not done by specifying an empty value
|
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`)
|
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`)
|
CommitGroupBy string // Property name of `Commit` to be grouped into `CommitGroup` (e.g. `Type`)
|
||||||
CommitGroupSortBy string // Property name to use for sorting `CommitGroup` (e.g. `Title`)
|
CommitGroupSortBy string // Property name to use for sorting `CommitGroup` (e.g. `Title`)
|
||||||
CommitGroupTitleOrder []string // Predefined sorted list of titles to use for sorting `CommitGroup`. Only if `CommitGroupSortBy` is `Custom`
|
CommitGroupTitleOrder []string // Predefined sorted list of titles to use for sorting `CommitGroup`. Only if `CommitGroupSortBy` is `Custom`
|
||||||
CommitGroupTitleMaps map[string]string // Map for `CommitGroup` title conversion
|
CommitGroupTitleMaps map[string]string // Map for `CommitGroup` title conversion
|
||||||
HeaderPattern string // A regular expression to use for parsing the commit header
|
HeaderPattern string // A regular expression to use for parsing the commit header
|
||||||
HeaderPatternMaps []string // A rule for mapping the result of `HeaderPattern` to the property of `Commit`
|
HeaderPatternMaps []string // A rule for mapping the result of `HeaderPattern` to the property of `Commit`
|
||||||
IssuePrefix []string // Prefix used for issues (e.g. `#`, `gh-`)
|
IssuePrefix []string // Prefix used for issues (e.g. `#`, `gh-`)
|
||||||
RefActions []string // Word list of `Ref.Action`
|
RefActions []string // Word list of `Ref.Action`
|
||||||
MergePattern string // A regular expression to use for parsing the merge commit
|
MergePattern string // A regular expression to use for parsing the merge commit
|
||||||
MergePatternMaps []string // Similar to `HeaderPatternMaps`
|
MergePatternMaps []string // Similar to `HeaderPatternMaps`
|
||||||
RevertPattern string // A regular expression to use for parsing the revert commit
|
RevertPattern string // A regular expression to use for parsing the revert commit
|
||||||
RevertPatternMaps []string // Similar to `HeaderPatternMaps`
|
RevertPatternMaps []string // Similar to `HeaderPatternMaps`
|
||||||
NoteKeywords []string // Keyword list to find `Note`. A semicolon is a separator, like `<keyword>:` (e.g. `BREAKING CHANGE`)
|
NoteKeywords []string // Keyword list to find `Note`. A semicolon is a separator, like `<keyword>:` (e.g. `BREAKING CHANGE`)
|
||||||
|
JiraUsername string
|
||||||
|
JiraToken string
|
||||||
|
JiraUrl string
|
||||||
|
JiraTypeMaps map[string]string
|
||||||
|
JiraIssueDescriptionPattern string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info is metadata related to CHANGELOG
|
// Info is metadata related to CHANGELOG
|
||||||
|
|
@ -97,11 +102,13 @@ type Generator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGenerator receives `Config` and create an new `Generator`
|
// NewGenerator receives `Config` and create an new `Generator`
|
||||||
func NewGenerator(config *Config) *Generator {
|
func NewGenerator(logger *Logger, config *Config) *Generator {
|
||||||
client := gitcmd.New(&gitcmd.Config{
|
client := gitcmd.New(&gitcmd.Config{
|
||||||
Bin: config.Bin,
|
Bin: config.Bin,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
jiraClient := NewJiraClient(config)
|
||||||
|
|
||||||
if config.Options.Processor != nil {
|
if config.Options.Processor != nil {
|
||||||
config.Options.Processor.Bootstrap(config)
|
config.Options.Processor.Bootstrap(config)
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +120,7 @@ func NewGenerator(config *Config) *Generator {
|
||||||
config: config,
|
config: config,
|
||||||
tagReader: newTagReader(client, config.Options.TagFilterPattern),
|
tagReader: newTagReader(client, config.Options.TagFilterPattern),
|
||||||
tagSelector: newTagSelector(),
|
tagSelector: newTagSelector(),
|
||||||
commitParser: newCommitParser(client, config),
|
commitParser: newCommitParser(logger, client, jiraClient, config),
|
||||||
commitExtractor: newCommitExtractor(config.Options),
|
commitExtractor: newCommitExtractor(config.Options),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
312
chglog_test.go
312
chglog_test.go
|
|
@ -76,15 +76,16 @@ func TestGeneratorNotFoundTags(t *testing.T) {
|
||||||
commit("2018-01-01 00:00:00", "feat(*): New feature", "")
|
commit("2018-01-01 00:00:00", "feat(*): New feature", "")
|
||||||
})
|
})
|
||||||
|
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: filepath.Join(testRepoRoot, testName),
|
Bin: "git",
|
||||||
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
WorkingDir: filepath.Join(testRepoRoot, testName),
|
||||||
Info: &Info{
|
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Info: &Info{
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{},
|
},
|
||||||
})
|
Options: &Options{},
|
||||||
|
})
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
|
|
@ -102,15 +103,16 @@ func TestGeneratorNotFoundCommits(t *testing.T) {
|
||||||
tag("1.0.0")
|
tag("1.0.0")
|
||||||
})
|
})
|
||||||
|
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: filepath.Join(testRepoRoot, testName),
|
Bin: "git",
|
||||||
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
WorkingDir: filepath.Join(testRepoRoot, testName),
|
||||||
Info: &Info{
|
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Info: &Info{
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{},
|
},
|
||||||
})
|
Options: &Options{},
|
||||||
|
})
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "foo")
|
err := gen.Generate(buf, "foo")
|
||||||
|
|
@ -127,44 +129,45 @@ func TestGeneratorNotFoundCommitsOne(t *testing.T) {
|
||||||
tag("1.0.0")
|
tag("1.0.0")
|
||||||
})
|
})
|
||||||
|
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: filepath.Join(testRepoRoot, testName),
|
Bin: "git",
|
||||||
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
WorkingDir: filepath.Join(testRepoRoot, testName),
|
||||||
Info: &Info{
|
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Info: &Info{
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{
|
|
||||||
CommitFilters: map[string][]string{},
|
|
||||||
CommitSortBy: "Scope",
|
|
||||||
CommitGroupBy: "Type",
|
|
||||||
CommitGroupSortBy: "Title",
|
|
||||||
CommitGroupTitleMaps: map[string]string{},
|
|
||||||
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
|
||||||
HeaderPatternMaps: []string{
|
|
||||||
"Type",
|
|
||||||
"Scope",
|
|
||||||
"Subject",
|
|
||||||
},
|
},
|
||||||
IssuePrefix: []string{
|
Options: &Options{
|
||||||
"#",
|
CommitFilters: map[string][]string{},
|
||||||
"gh-",
|
CommitSortBy: "Scope",
|
||||||
|
CommitGroupBy: "Type",
|
||||||
|
CommitGroupSortBy: "Title",
|
||||||
|
CommitGroupTitleMaps: map[string]string{},
|
||||||
|
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
||||||
|
HeaderPatternMaps: []string{
|
||||||
|
"Type",
|
||||||
|
"Scope",
|
||||||
|
"Subject",
|
||||||
|
},
|
||||||
|
IssuePrefix: []string{
|
||||||
|
"#",
|
||||||
|
"gh-",
|
||||||
|
},
|
||||||
|
RefActions: []string{},
|
||||||
|
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
||||||
|
MergePatternMaps: []string{
|
||||||
|
"Ref",
|
||||||
|
"Source",
|
||||||
|
},
|
||||||
|
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
||||||
|
RevertPatternMaps: []string{
|
||||||
|
"Header",
|
||||||
|
},
|
||||||
|
NoteKeywords: []string{
|
||||||
|
"BREAKING CHANGE",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
RefActions: []string{},
|
})
|
||||||
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
|
||||||
MergePatternMaps: []string{
|
|
||||||
"Ref",
|
|
||||||
"Source",
|
|
||||||
},
|
|
||||||
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
|
||||||
RevertPatternMaps: []string{
|
|
||||||
"Header",
|
|
||||||
},
|
|
||||||
NoteKeywords: []string{
|
|
||||||
"BREAKING CHANGE",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "foo")
|
err := gen.Generate(buf, "foo")
|
||||||
|
|
@ -202,53 +205,54 @@ change message.`)
|
||||||
commit("2018-01-04 00:01:00", "fix(core): Fix commit\n\nThis is body message.", "")
|
commit("2018-01-04 00:01:00", "fix(core): Fix commit\n\nThis is body message.", "")
|
||||||
})
|
})
|
||||||
|
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: filepath.Join(testRepoRoot, testName),
|
Bin: "git",
|
||||||
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
WorkingDir: filepath.Join(testRepoRoot, testName),
|
||||||
Info: &Info{
|
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
||||||
Title: "CHANGELOG Example",
|
Info: &Info{
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Title: "CHANGELOG Example",
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{
|
},
|
||||||
CommitFilters: map[string][]string{
|
Options: &Options{
|
||||||
"Type": []string{
|
CommitFilters: map[string][]string{
|
||||||
"feat",
|
"Type": []string{
|
||||||
"fix",
|
"feat",
|
||||||
|
"fix",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CommitSortBy: "Scope",
|
||||||
|
CommitGroupBy: "Type",
|
||||||
|
CommitGroupSortBy: "Title",
|
||||||
|
CommitGroupTitleMaps: map[string]string{
|
||||||
|
"feat": "Features",
|
||||||
|
"fix": "Bug Fixes",
|
||||||
|
},
|
||||||
|
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
||||||
|
HeaderPatternMaps: []string{
|
||||||
|
"Type",
|
||||||
|
"Scope",
|
||||||
|
"Subject",
|
||||||
|
},
|
||||||
|
IssuePrefix: []string{
|
||||||
|
"#",
|
||||||
|
"gh-",
|
||||||
|
},
|
||||||
|
RefActions: []string{},
|
||||||
|
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
||||||
|
MergePatternMaps: []string{
|
||||||
|
"Ref",
|
||||||
|
"Source",
|
||||||
|
},
|
||||||
|
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
||||||
|
RevertPatternMaps: []string{
|
||||||
|
"Header",
|
||||||
|
},
|
||||||
|
NoteKeywords: []string{
|
||||||
|
"BREAKING CHANGE",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CommitSortBy: "Scope",
|
})
|
||||||
CommitGroupBy: "Type",
|
|
||||||
CommitGroupSortBy: "Title",
|
|
||||||
CommitGroupTitleMaps: map[string]string{
|
|
||||||
"feat": "Features",
|
|
||||||
"fix": "Bug Fixes",
|
|
||||||
},
|
|
||||||
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
|
||||||
HeaderPatternMaps: []string{
|
|
||||||
"Type",
|
|
||||||
"Scope",
|
|
||||||
"Subject",
|
|
||||||
},
|
|
||||||
IssuePrefix: []string{
|
|
||||||
"#",
|
|
||||||
"gh-",
|
|
||||||
},
|
|
||||||
RefActions: []string{},
|
|
||||||
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
|
||||||
MergePatternMaps: []string{
|
|
||||||
"Ref",
|
|
||||||
"Source",
|
|
||||||
},
|
|
||||||
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
|
||||||
RevertPatternMaps: []string{
|
|
||||||
"Header",
|
|
||||||
},
|
|
||||||
NoteKeywords: []string{
|
|
||||||
"BREAKING CHANGE",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
|
|
@ -315,35 +319,36 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
||||||
commit("2018-03-01 00:00:00", "feat(core): version 3.0.0", "")
|
commit("2018-03-01 00:00:00", "feat(core): version 3.0.0", "")
|
||||||
})
|
})
|
||||||
|
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: filepath.Join(testRepoRoot, testName),
|
Bin: "git",
|
||||||
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
WorkingDir: filepath.Join(testRepoRoot, testName),
|
||||||
Info: &Info{
|
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
||||||
Title: "CHANGELOG Example",
|
Info: &Info{
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Title: "CHANGELOG Example",
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{
|
},
|
||||||
NextTag: "3.0.0",
|
Options: &Options{
|
||||||
CommitFilters: map[string][]string{
|
NextTag: "3.0.0",
|
||||||
"Type": []string{
|
CommitFilters: map[string][]string{
|
||||||
"feat",
|
"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",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
|
|
@ -407,35 +412,36 @@ func TestGeneratorWithTagFiler(t *testing.T) {
|
||||||
tag("v1.0.0")
|
tag("v1.0.0")
|
||||||
})
|
})
|
||||||
|
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: filepath.Join(testRepoRoot, testName),
|
Bin: "git",
|
||||||
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
WorkingDir: filepath.Join(testRepoRoot, testName),
|
||||||
Info: &Info{
|
Template: filepath.Join(cwd, "testdata", testName+".md"),
|
||||||
Title: "CHANGELOG Example",
|
Info: &Info{
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Title: "CHANGELOG Example",
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{
|
},
|
||||||
TagFilterPattern: "^v",
|
Options: &Options{
|
||||||
CommitFilters: map[string][]string{
|
TagFilterPattern: "^v",
|
||||||
"Type": []string{
|
CommitFilters: map[string][]string{
|
||||||
"feat",
|
"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",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
type CLI struct {
|
type CLI struct {
|
||||||
ctx *CLIContext
|
ctx *CLIContext
|
||||||
fs FileSystem
|
fs FileSystem
|
||||||
logger *Logger
|
logger *chglog.Logger
|
||||||
configLoader ConfigLoader
|
configLoader ConfigLoader
|
||||||
generator Generator
|
generator Generator
|
||||||
processorFactory *ProcessorFactory
|
processorFactory *ProcessorFactory
|
||||||
|
|
@ -34,7 +34,7 @@ func NewCLI(
|
||||||
return &CLI{
|
return &CLI{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
fs: fs,
|
fs: fs,
|
||||||
logger: NewLogger(ctx.Stdout, ctx.Stderr, silent, ctx.NoEmoji),
|
logger: chglog.NewLogger(ctx.Stdout, ctx.Stderr, silent, ctx.NoEmoji),
|
||||||
configLoader: configLoader,
|
configLoader: configLoader,
|
||||||
generator: generator,
|
generator: generator,
|
||||||
processorFactory: NewProcessorFactory(),
|
processorFactory: NewProcessorFactory(),
|
||||||
|
|
@ -69,7 +69,7 @@ func (c *CLI) Run() int {
|
||||||
return ExitCodeError
|
return ExitCodeError
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.generator.Generate(w, c.ctx.Query, changelogConfig)
|
err = c.generator.Generate(c.logger, w, c.ctx.Query, changelogConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error(err.Error())
|
c.logger.Error(err.Error())
|
||||||
return ExitCodeError
|
return ExitCodeError
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,24 @@ type NoteOptions struct {
|
||||||
Keywords []string `yaml:"keywords"`
|
Keywords []string `yaml:"keywords"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JiraClientInfoOptions struct {
|
||||||
|
Username string `yaml:"username"`
|
||||||
|
Token string `yaml:"token"`
|
||||||
|
URL string `yaml:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JiraIssueOptions ...
|
||||||
|
type JiraIssueOptions struct {
|
||||||
|
TypeMaps map[string]string `yaml:"type_maps"`
|
||||||
|
DescriptionPattern string `yaml:"description_pattern"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JiraOptions ...
|
||||||
|
type JiraOptions struct {
|
||||||
|
ClintInfo JiraClientInfoOptions `yaml:"info"`
|
||||||
|
Issue JiraIssueOptions `yaml:"issue"`
|
||||||
|
}
|
||||||
|
|
||||||
// Options ...
|
// Options ...
|
||||||
type Options struct {
|
type Options struct {
|
||||||
TagFilterPattern string `yaml:"tag_filter_pattern"`
|
TagFilterPattern string `yaml:"tag_filter_pattern"`
|
||||||
|
|
@ -60,6 +78,7 @@ type Options struct {
|
||||||
Merges PatternOptions `yaml:"merges"`
|
Merges PatternOptions `yaml:"merges"`
|
||||||
Reverts PatternOptions `yaml:"reverts"`
|
Reverts PatternOptions `yaml:"reverts"`
|
||||||
Notes NoteOptions `yaml:"notes"`
|
Notes NoteOptions `yaml:"notes"`
|
||||||
|
Jira JiraOptions `yaml:"jira"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config ...
|
// Config ...
|
||||||
|
|
@ -245,6 +264,13 @@ func (config *Config) normalizeStyleOfBitbucket() {
|
||||||
config.Options = opts
|
config.Options = opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orValue(str1 string, str2 string) string {
|
||||||
|
if str1 != "" {
|
||||||
|
return str1
|
||||||
|
}
|
||||||
|
return str2
|
||||||
|
}
|
||||||
|
|
||||||
// Convert ...
|
// Convert ...
|
||||||
func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
||||||
info := config.Info
|
info := config.Info
|
||||||
|
|
@ -257,30 +283,34 @@ func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
||||||
return &chglog.Config{
|
return &chglog.Config{
|
||||||
Bin: config.Bin,
|
Bin: config.Bin,
|
||||||
WorkingDir: ctx.WorkingDir,
|
WorkingDir: ctx.WorkingDir,
|
||||||
Template: config.Template,
|
Template: orValue(ctx.Template, config.Template),
|
||||||
Info: &chglog.Info{
|
Info: &chglog.Info{
|
||||||
Title: info.Title,
|
Title: info.Title,
|
||||||
RepositoryURL: info.RepositoryURL,
|
RepositoryURL: orValue(ctx.RepositoryUrl, info.RepositoryURL),
|
||||||
},
|
},
|
||||||
Options: &chglog.Options{
|
Options: &chglog.Options{
|
||||||
NextTag: ctx.NextTag,
|
NextTag: ctx.NextTag,
|
||||||
TagFilterPattern: ctx.TagFilterPattern,
|
TagFilterPattern: ctx.TagFilterPattern,
|
||||||
NoCaseSensitive: ctx.NoCaseSensitive,
|
NoCaseSensitive: ctx.NoCaseSensitive,
|
||||||
CommitFilters: opts.Commits.Filters,
|
CommitFilters: opts.Commits.Filters,
|
||||||
CommitSortBy: opts.Commits.SortBy,
|
CommitSortBy: opts.Commits.SortBy,
|
||||||
CommitGroupBy: opts.CommitGroups.GroupBy,
|
CommitGroupBy: opts.CommitGroups.GroupBy,
|
||||||
CommitGroupSortBy: opts.CommitGroups.SortBy,
|
CommitGroupSortBy: opts.CommitGroups.SortBy,
|
||||||
CommitGroupTitleMaps: opts.CommitGroups.TitleMaps,
|
CommitGroupTitleMaps: opts.CommitGroups.TitleMaps,
|
||||||
CommitGroupTitleOrder: opts.CommitGroups.TitleOrder,
|
HeaderPattern: opts.Header.Pattern,
|
||||||
HeaderPattern: opts.Header.Pattern,
|
HeaderPatternMaps: opts.Header.PatternMaps,
|
||||||
HeaderPatternMaps: opts.Header.PatternMaps,
|
IssuePrefix: opts.Issues.Prefix,
|
||||||
IssuePrefix: opts.Issues.Prefix,
|
RefActions: opts.Refs.Actions,
|
||||||
RefActions: opts.Refs.Actions,
|
MergePattern: opts.Merges.Pattern,
|
||||||
MergePattern: opts.Merges.Pattern,
|
MergePatternMaps: opts.Merges.PatternMaps,
|
||||||
MergePatternMaps: opts.Merges.PatternMaps,
|
RevertPattern: opts.Reverts.Pattern,
|
||||||
RevertPattern: opts.Reverts.Pattern,
|
RevertPatternMaps: opts.Reverts.PatternMaps,
|
||||||
RevertPatternMaps: opts.Reverts.PatternMaps,
|
NoteKeywords: opts.Notes.Keywords,
|
||||||
NoteKeywords: opts.Notes.Keywords,
|
JiraUsername: orValue(ctx.JiraUsername, opts.Jira.ClintInfo.Username),
|
||||||
|
JiraToken: orValue(ctx.JiraToken, opts.Jira.ClintInfo.Token),
|
||||||
|
JiraUrl: orValue(ctx.JiraUrl, opts.Jira.ClintInfo.URL),
|
||||||
|
JiraTypeMaps: opts.Jira.Issue.TypeMaps,
|
||||||
|
JiraIssueDescriptionPattern: opts.Jira.Issue.DescriptionPattern,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ type CLIContext struct {
|
||||||
Stdout io.Writer
|
Stdout io.Writer
|
||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
ConfigPath string
|
ConfigPath string
|
||||||
|
Template string
|
||||||
|
RepositoryUrl string
|
||||||
OutputPath string
|
OutputPath string
|
||||||
Silent bool
|
Silent bool
|
||||||
NoColor bool
|
NoColor bool
|
||||||
|
|
@ -18,6 +20,9 @@ type CLIContext struct {
|
||||||
Query string
|
Query string
|
||||||
NextTag string
|
NextTag string
|
||||||
TagFilterPattern string
|
TagFilterPattern string
|
||||||
|
JiraUsername string
|
||||||
|
JiraToken string
|
||||||
|
JiraUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitContext ...
|
// InitContext ...
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
// Generator ...
|
// Generator ...
|
||||||
type Generator interface {
|
type Generator interface {
|
||||||
Generate(io.Writer, string, *chglog.Config) error
|
Generate(*chglog.Logger, io.Writer, string, *chglog.Config) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type generatorImpl struct{}
|
type generatorImpl struct{}
|
||||||
|
|
@ -19,6 +19,6 @@ func NewGenerator() Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate ...
|
// Generate ...
|
||||||
func (*generatorImpl) Generate(w io.Writer, query string, config *chglog.Config) error {
|
func (*generatorImpl) Generate(logger *chglog.Logger, w io.Writer, query string, config *chglog.Config) error {
|
||||||
return chglog.NewGenerator(config).Generate(w, query)
|
return chglog.NewGenerator(logger, config).Generate(w, query)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,6 @@ type mockGeneratorImpl struct {
|
||||||
ReturnGenerate func(io.Writer, string, *chglog.Config) error
|
ReturnGenerate func(io.Writer, string, *chglog.Config) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockGeneratorImpl) Generate(w io.Writer, query string, config *chglog.Config) error {
|
func (m *mockGeneratorImpl) Generate(logger *chglog.Logger, w io.Writer, query string, config *chglog.Config) error {
|
||||||
return m.ReturnGenerate(w, query, config)
|
return m.ReturnGenerate(w, query, config)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/git-chglog/git-chglog"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
|
@ -13,7 +14,7 @@ type Initializer struct {
|
||||||
ctx *InitContext
|
ctx *InitContext
|
||||||
client gitcmd.Client
|
client gitcmd.Client
|
||||||
fs FileSystem
|
fs FileSystem
|
||||||
logger *Logger
|
logger *chglog.Logger
|
||||||
questioner Questioner
|
questioner Questioner
|
||||||
configBuilder ConfigBuilder
|
configBuilder ConfigBuilder
|
||||||
templateBuilderFactory TemplateBuilderFactory
|
templateBuilderFactory TemplateBuilderFactory
|
||||||
|
|
@ -29,7 +30,7 @@ func NewInitializer(
|
||||||
return &Initializer{
|
return &Initializer{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
fs: fs,
|
fs: fs,
|
||||||
logger: NewLogger(ctx.Stdout, ctx.Stderr, false, false),
|
logger: chglog.NewLogger(ctx.Stdout, ctx.Stderr, false, false),
|
||||||
questioner: questioner,
|
questioner: questioner,
|
||||||
configBuilder: configBuilder,
|
configBuilder: configBuilder,
|
||||||
templateBuilderFactory: tplBuilderFactory,
|
templateBuilderFactory: tplBuilderFactory,
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,18 @@ func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||||
Value: ".chglog/config.yml",
|
Value: ".chglog/config.yml",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// template
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "template, t",
|
||||||
|
Usage: "specifies a template file to pick up. If not specified, use the one in config",
|
||||||
|
},
|
||||||
|
|
||||||
|
// repository url
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "repository-url",
|
||||||
|
Usage: "specifies git repo URL. If not specified, use 'repository_url' in config",
|
||||||
|
},
|
||||||
|
|
||||||
// output
|
// output
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "output, o",
|
Name: "output, o",
|
||||||
|
|
@ -102,15 +114,15 @@ func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||||
|
|
||||||
// no-color
|
// no-color
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "no-color",
|
Name: "no-color",
|
||||||
Usage: "disable color output",
|
Usage: "disable color output",
|
||||||
EnvVars: []string{"NO_COLOR"},
|
EnvVars: []string{"NO_COLOR"},
|
||||||
},
|
},
|
||||||
|
|
||||||
// no-emoji
|
// no-emoji
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "no-emoji",
|
Name: "no-emoji",
|
||||||
Usage: "disable emoji output",
|
Usage: "disable emoji output",
|
||||||
EnvVars: []string{"NO_EMOJI"},
|
EnvVars: []string{"NO_EMOJI"},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -122,10 +134,31 @@ func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||||
|
|
||||||
// tag-filter-pattern
|
// tag-filter-pattern
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "tag-filter-pattern, p",
|
Name: "tag-filter-pattern",
|
||||||
Usage: "Regular expression of tag filter. Is specified, only matched tags will be picked",
|
Usage: "Regular expression of tag filter. Is specified, only matched tags will be picked",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// jira-url
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "jira-url",
|
||||||
|
Usage: "Jira URL",
|
||||||
|
EnvVars: []string{"JIRA_URL"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// jira-username
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "jira-username",
|
||||||
|
Usage: "Jira username",
|
||||||
|
EnvVars: []string{"JIRA_USERNAME"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// jira-token
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "jira-token",
|
||||||
|
Usage: "Jira token",
|
||||||
|
EnvVars: []string{"JIRA_TOKEN"},
|
||||||
|
},
|
||||||
|
|
||||||
// help & version
|
// help & version
|
||||||
cli.HelpFlag,
|
cli.HelpFlag,
|
||||||
cli.VersionFlag,
|
cli.VersionFlag,
|
||||||
|
|
@ -180,6 +213,9 @@ func AppAction(c *cli.Context) error {
|
||||||
Query: c.Args().First(),
|
Query: c.Args().First(),
|
||||||
NextTag: c.String("next-tag"),
|
NextTag: c.String("next-tag"),
|
||||||
TagFilterPattern: c.String("tag-filter-pattern"),
|
TagFilterPattern: c.String("tag-filter-pattern"),
|
||||||
|
JiraUsername: c.String("jira-username"),
|
||||||
|
JiraToken: c.String("jira-token"),
|
||||||
|
JiraUrl: c.String("jira-url"),
|
||||||
},
|
},
|
||||||
fs,
|
fs,
|
||||||
NewConfigLoader(),
|
NewConfigLoader(),
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
package chglog
|
package chglog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
"github.com/tsuyoshiwada/go-gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -47,18 +48,21 @@ func joinAndQuoteMeta(list []string, sep string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type commitParser struct {
|
type commitParser struct {
|
||||||
client gitcmd.Client
|
logger *Logger
|
||||||
config *Config
|
client gitcmd.Client
|
||||||
reHeader *regexp.Regexp
|
jiraClient JiraClient
|
||||||
reMerge *regexp.Regexp
|
config *Config
|
||||||
reRevert *regexp.Regexp
|
reHeader *regexp.Regexp
|
||||||
reRef *regexp.Regexp
|
reMerge *regexp.Regexp
|
||||||
reIssue *regexp.Regexp
|
reRevert *regexp.Regexp
|
||||||
reNotes *regexp.Regexp
|
reRef *regexp.Regexp
|
||||||
reMention *regexp.Regexp
|
reIssue *regexp.Regexp
|
||||||
|
reNotes *regexp.Regexp
|
||||||
|
reMention *regexp.Regexp
|
||||||
|
reJiraIssueDescription *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCommitParser(client gitcmd.Client, config *Config) *commitParser {
|
func newCommitParser(logger *Logger, client gitcmd.Client, jiraClient JiraClient, config *Config) *commitParser {
|
||||||
opts := config.Options
|
opts := config.Options
|
||||||
|
|
||||||
joinedRefActions := joinAndQuoteMeta(opts.RefActions, "|")
|
joinedRefActions := joinAndQuoteMeta(opts.RefActions, "|")
|
||||||
|
|
@ -66,15 +70,18 @@ func newCommitParser(client gitcmd.Client, config *Config) *commitParser {
|
||||||
joinedNoteKeywords := joinAndQuoteMeta(opts.NoteKeywords, "|")
|
joinedNoteKeywords := joinAndQuoteMeta(opts.NoteKeywords, "|")
|
||||||
|
|
||||||
return &commitParser{
|
return &commitParser{
|
||||||
client: client,
|
logger: logger,
|
||||||
config: config,
|
client: client,
|
||||||
reHeader: regexp.MustCompile(opts.HeaderPattern),
|
jiraClient: jiraClient,
|
||||||
reMerge: regexp.MustCompile(opts.MergePattern),
|
config: config,
|
||||||
reRevert: regexp.MustCompile(opts.RevertPattern),
|
reHeader: regexp.MustCompile(opts.HeaderPattern),
|
||||||
reRef: regexp.MustCompile("(?i)(" + joinedRefActions + ")\\s?([\\w/\\.\\-]+)?(?:" + joinedIssuePrefix + ")(\\d+)"),
|
reMerge: regexp.MustCompile(opts.MergePattern),
|
||||||
reIssue: regexp.MustCompile("(?:" + joinedIssuePrefix + ")(\\d+)"),
|
reRevert: regexp.MustCompile(opts.RevertPattern),
|
||||||
reNotes: regexp.MustCompile("^(?i)\\s*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
|
reRef: regexp.MustCompile("(?i)(" + joinedRefActions + ")\\s?([\\w/\\.\\-]+)?(?:" + joinedIssuePrefix + ")(\\d+)"),
|
||||||
reMention: regexp.MustCompile("@([\\w-]+)"),
|
reIssue: regexp.MustCompile("(?:" + joinedIssuePrefix + ")(\\d+)"),
|
||||||
|
reNotes: regexp.MustCompile("^(?i)\\s*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
|
||||||
|
reMention: regexp.MustCompile("@([\\w-]+)"),
|
||||||
|
reJiraIssueDescription: regexp.MustCompile(opts.JiraIssueDescriptionPattern),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,6 +213,11 @@ func (p *commitParser) processHeader(commit *Commit, input string) {
|
||||||
// refs & mentions
|
// refs & mentions
|
||||||
commit.Refs = p.parseRefs(input)
|
commit.Refs = p.parseRefs(input)
|
||||||
commit.Mentions = p.parseMentions(input)
|
commit.Mentions = p.parseMentions(input)
|
||||||
|
|
||||||
|
// Jira
|
||||||
|
if commit.JiraIssueId != "" {
|
||||||
|
p.processJiraIssue(commit, commit.JiraIssueId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *commitParser) processBody(commit *Commit, input string) {
|
func (p *commitParser) processBody(commit *Commit, input string) {
|
||||||
|
|
@ -344,6 +356,28 @@ func (p *commitParser) uniqMentions(mentions []string) []string {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *commitParser) processJiraIssue(commit *Commit, issueId string) {
|
||||||
|
issue, err := p.jiraClient.GetJiraIssue(commit.JiraIssueId)
|
||||||
|
if err != nil {
|
||||||
|
p.logger.Error(fmt.Sprintf("Failed to parse Jira story %s: %s\n", issueId, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
commit.Type = p.config.Options.JiraTypeMaps[issue.Fields.Type.Name]
|
||||||
|
commit.JiraIssue = &JiraIssue{
|
||||||
|
Type: issue.Fields.Type.Name,
|
||||||
|
Summary: issue.Fields.Summary,
|
||||||
|
Description: issue.Fields.Description,
|
||||||
|
Labels: issue.Fields.Labels,
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.config.Options.JiraIssueDescriptionPattern != "" {
|
||||||
|
res := p.reJiraIssueDescription.FindStringSubmatch(commit.JiraIssue.Description)
|
||||||
|
if len(res) > 1 {
|
||||||
|
commit.JiraIssue.Description = res[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fenceTypes = []string{
|
fenceTypes = []string{
|
||||||
"```",
|
"```",
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
agjira "github.com/andygrunwald/go-jira"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -27,51 +29,52 @@ func TestCommitParserParse(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
parser := newCommitParser(mock, &Config{
|
parser := newCommitParser(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Options: &Options{
|
mock, nil, &Config{
|
||||||
CommitFilters: map[string][]string{
|
Options: &Options{
|
||||||
"Type": []string{
|
CommitFilters: map[string][]string{
|
||||||
"feat",
|
"Type": []string{
|
||||||
|
"feat",
|
||||||
|
"fix",
|
||||||
|
"perf",
|
||||||
|
"refactor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
||||||
|
HeaderPatternMaps: []string{
|
||||||
|
"Type",
|
||||||
|
"Scope",
|
||||||
|
"Subject",
|
||||||
|
},
|
||||||
|
IssuePrefix: []string{
|
||||||
|
"#",
|
||||||
|
"gh-",
|
||||||
|
},
|
||||||
|
RefActions: []string{
|
||||||
|
"close",
|
||||||
|
"closes",
|
||||||
|
"closed",
|
||||||
"fix",
|
"fix",
|
||||||
"perf",
|
"fixes",
|
||||||
"refactor",
|
"fixed",
|
||||||
|
"resolve",
|
||||||
|
"resolves",
|
||||||
|
"resolved",
|
||||||
|
},
|
||||||
|
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
||||||
|
MergePatternMaps: []string{
|
||||||
|
"Ref",
|
||||||
|
"Source",
|
||||||
|
},
|
||||||
|
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
||||||
|
RevertPatternMaps: []string{
|
||||||
|
"Header",
|
||||||
|
},
|
||||||
|
NoteKeywords: []string{
|
||||||
|
"BREAKING CHANGE",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
})
|
||||||
HeaderPatternMaps: []string{
|
|
||||||
"Type",
|
|
||||||
"Scope",
|
|
||||||
"Subject",
|
|
||||||
},
|
|
||||||
IssuePrefix: []string{
|
|
||||||
"#",
|
|
||||||
"gh-",
|
|
||||||
},
|
|
||||||
RefActions: []string{
|
|
||||||
"close",
|
|
||||||
"closes",
|
|
||||||
"closed",
|
|
||||||
"fix",
|
|
||||||
"fixes",
|
|
||||||
"fixed",
|
|
||||||
"resolve",
|
|
||||||
"resolves",
|
|
||||||
"resolved",
|
|
||||||
},
|
|
||||||
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
|
||||||
MergePatternMaps: []string{
|
|
||||||
"Ref",
|
|
||||||
"Source",
|
|
||||||
},
|
|
||||||
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
|
||||||
RevertPatternMaps: []string{
|
|
||||||
"Header",
|
|
||||||
},
|
|
||||||
NoteKeywords: []string{
|
|
||||||
"BREAKING CHANGE",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
commits, err := parser.Parse("HEAD")
|
commits, err := parser.Parse("HEAD")
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
|
|
@ -308,3 +311,102 @@ Closes username/repository#456`, "```", "```"),
|
||||||
},
|
},
|
||||||
}, commits)
|
}, commits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockJiraClient struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jira mockJiraClient) GetJiraIssue(id string) (*agjira.Issue, error) {
|
||||||
|
return &agjira.Issue{
|
||||||
|
ID: id,
|
||||||
|
Fields: &agjira.IssueFields{
|
||||||
|
Expand: "",
|
||||||
|
Type: agjira.IssueType{Name: "Story"},
|
||||||
|
Project: agjira.Project{},
|
||||||
|
Resolution: nil,
|
||||||
|
Priority: nil,
|
||||||
|
Resolutiondate: agjira.Time{},
|
||||||
|
Created: agjira.Time{},
|
||||||
|
Duedate: agjira.Date{},
|
||||||
|
Watches: nil,
|
||||||
|
Assignee: nil,
|
||||||
|
Updated: agjira.Time{},
|
||||||
|
Description: fmt.Sprintf("description of %s", id),
|
||||||
|
Summary: fmt.Sprintf("summary of %s", id),
|
||||||
|
Creator: nil,
|
||||||
|
Reporter: nil,
|
||||||
|
Components: nil,
|
||||||
|
Status: nil,
|
||||||
|
Progress: nil,
|
||||||
|
AggregateProgress: nil,
|
||||||
|
TimeTracking: nil,
|
||||||
|
TimeSpent: 0,
|
||||||
|
TimeEstimate: 0,
|
||||||
|
TimeOriginalEstimate: 0,
|
||||||
|
Worklog: nil,
|
||||||
|
IssueLinks: nil,
|
||||||
|
Comments: nil,
|
||||||
|
FixVersions: nil,
|
||||||
|
AffectsVersions: nil,
|
||||||
|
Labels: []string{"GA"},
|
||||||
|
Subtasks: nil,
|
||||||
|
Attachments: nil,
|
||||||
|
Epic: nil,
|
||||||
|
Sprint: nil,
|
||||||
|
Parent: nil,
|
||||||
|
AggregateTimeOriginalEstimate: 0,
|
||||||
|
AggregateTimeSpent: 0,
|
||||||
|
AggregateTimeEstimate: 0,
|
||||||
|
Unknowns: nil,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitParserParseWithJira(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
assert.True(true)
|
||||||
|
|
||||||
|
mock := &mockClient{
|
||||||
|
ReturnExec: func(subcmd string, args ...string) (string, error) {
|
||||||
|
if subcmd != "log" {
|
||||||
|
return "", errors.New("")
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, _ := ioutil.ReadFile(filepath.Join("testdata", "gitlog_jira.txt"))
|
||||||
|
|
||||||
|
return string(bytes), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
parser := newCommitParser(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
|
mock, mockJiraClient{}, &Config{
|
||||||
|
Options: &Options{
|
||||||
|
CommitFilters: map[string][]string{
|
||||||
|
"Type": []string{
|
||||||
|
"feat",
|
||||||
|
"fix",
|
||||||
|
"perf",
|
||||||
|
"refactor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HeaderPattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$",
|
||||||
|
HeaderPatternMaps: []string{
|
||||||
|
"Type",
|
||||||
|
"JiraIssueId",
|
||||||
|
"Subject",
|
||||||
|
},
|
||||||
|
JiraTypeMaps: map[string]string{
|
||||||
|
"Story": "feat",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
commits, err := parser.Parse("HEAD")
|
||||||
|
assert.Nil(err)
|
||||||
|
commit := commits[0]
|
||||||
|
assert.Equal(commit.JiraIssueId, "JIRA-1111")
|
||||||
|
assert.Equal(commit.JiraIssue.Type, "Story")
|
||||||
|
assert.Equal(commit.JiraIssue.Summary, "summary of JIRA-1111")
|
||||||
|
assert.Equal(commit.JiraIssue.Description, "description of JIRA-1111")
|
||||||
|
assert.Equal(commit.JiraIssue.Labels, []string{"GA"})
|
||||||
|
assert.Equal(commit.Type, "feat")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,56 +4,58 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Example() {
|
func Example() {
|
||||||
gen := NewGenerator(&Config{
|
gen := NewGenerator(NewLogger(os.Stdout, os.Stderr, false, true),
|
||||||
Bin: "git",
|
&Config{
|
||||||
WorkingDir: ".",
|
Bin: "git",
|
||||||
Template: "CHANGELOG.tpl.md",
|
WorkingDir: ".",
|
||||||
Info: &Info{
|
Template: "CHANGELOG.tpl.md",
|
||||||
Title: "CHANGELOG",
|
Info: &Info{
|
||||||
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
Title: "CHANGELOG",
|
||||||
},
|
RepositoryURL: "https://github.com/git-chglog/git-chglog",
|
||||||
Options: &Options{
|
},
|
||||||
CommitFilters: map[string][]string{
|
Options: &Options{
|
||||||
"Type": []string{
|
CommitFilters: map[string][]string{
|
||||||
"feat",
|
"Type": []string{
|
||||||
"fix",
|
"feat",
|
||||||
|
"fix",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CommitSortBy: "Scope",
|
||||||
|
CommitGroupBy: "Type",
|
||||||
|
CommitGroupSortBy: "Title",
|
||||||
|
CommitGroupTitleMaps: map[string]string{
|
||||||
|
"feat": "Features",
|
||||||
|
"fix": "Bug Fixes",
|
||||||
|
},
|
||||||
|
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
||||||
|
HeaderPatternMaps: []string{
|
||||||
|
"Type",
|
||||||
|
"Scope",
|
||||||
|
"Subject",
|
||||||
|
},
|
||||||
|
IssuePrefix: []string{
|
||||||
|
"#",
|
||||||
|
"gh-",
|
||||||
|
},
|
||||||
|
RefActions: []string{},
|
||||||
|
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
||||||
|
MergePatternMaps: []string{
|
||||||
|
"Ref",
|
||||||
|
"Source",
|
||||||
|
},
|
||||||
|
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
||||||
|
RevertPatternMaps: []string{
|
||||||
|
"Header",
|
||||||
|
},
|
||||||
|
NoteKeywords: []string{
|
||||||
|
"BREAKING CHANGE",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CommitSortBy: "Scope",
|
})
|
||||||
CommitGroupBy: "Type",
|
|
||||||
CommitGroupSortBy: "Title",
|
|
||||||
CommitGroupTitleMaps: map[string]string{
|
|
||||||
"feat": "Features",
|
|
||||||
"fix": "Bug Fixes",
|
|
||||||
},
|
|
||||||
HeaderPattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$",
|
|
||||||
HeaderPatternMaps: []string{
|
|
||||||
"Type",
|
|
||||||
"Scope",
|
|
||||||
"Subject",
|
|
||||||
},
|
|
||||||
IssuePrefix: []string{
|
|
||||||
"#",
|
|
||||||
"gh-",
|
|
||||||
},
|
|
||||||
RefActions: []string{},
|
|
||||||
MergePattern: "^Merge pull request #(\\d+) from (.*)$",
|
|
||||||
MergePatternMaps: []string{
|
|
||||||
"Ref",
|
|
||||||
"Source",
|
|
||||||
},
|
|
||||||
RevertPattern: "^Revert \"([\\s\\S]*)\"$",
|
|
||||||
RevertPatternMaps: []string{
|
|
||||||
"Header",
|
|
||||||
},
|
|
||||||
NoteKeywords: []string{
|
|
||||||
"BREAKING CHANGE",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
|
|
|
||||||
36
fields.go
36
fields.go
|
|
@ -52,21 +52,31 @@ type NoteGroup struct {
|
||||||
Notes []*Note
|
Notes []*Note
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JiraIssue
|
||||||
|
type JiraIssue struct {
|
||||||
|
Type string
|
||||||
|
Summary string
|
||||||
|
Description string
|
||||||
|
Labels []string
|
||||||
|
}
|
||||||
|
|
||||||
// Commit data
|
// Commit data
|
||||||
type Commit struct {
|
type Commit struct {
|
||||||
Hash *Hash
|
Hash *Hash
|
||||||
Author *Author
|
Author *Author
|
||||||
Committer *Committer
|
Committer *Committer
|
||||||
Merge *Merge // If it is not a merge commit, `nil` is assigned
|
Merge *Merge // If it is not a merge commit, `nil` is assigned
|
||||||
Revert *Revert // If it is not a revert commit, `nil` is assigned
|
Revert *Revert // If it is not a revert commit, `nil` is assigned
|
||||||
Refs []*Ref
|
Refs []*Ref
|
||||||
Notes []*Note
|
Notes []*Note
|
||||||
Mentions []string // Name of the user included in the commit header or body
|
Mentions []string // Name of the user included in the commit header or body
|
||||||
Header string // (e.g. `feat(core): Add new feature`)
|
JiraIssue *JiraIssue // If no issue id found in header, `nil` is assigned
|
||||||
Type string // (e.g. `feat`)
|
Header string // (e.g. `feat(core)[RNWY-310]: Add new feature`)
|
||||||
Scope string // (e.g. `core`)
|
Type string // (e.g. `feat`)
|
||||||
Subject string // (e.g. `Add new feature`)
|
Scope string // (e.g. `core`)
|
||||||
Body string
|
Subject string // (e.g. `Add new feature`)
|
||||||
|
JiraIssueId string // (e.g. `RNWY-310`)
|
||||||
|
Body string
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitGroup is a collection of commits grouped according to the `CommitGroupBy` option
|
// CommitGroup is a collection of commits grouped according to the `CommitGroupBy` option
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -4,6 +4,7 @@ go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlecAivazis/survey/v2 v2.2.8
|
github.com/AlecAivazis/survey/v2 v2.2.8
|
||||||
|
github.com/andygrunwald/go-jira v1.13.0
|
||||||
github.com/fatih/color v1.10.0
|
github.com/fatih/color v1.10.0
|
||||||
github.com/imdario/mergo v0.3.11
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/kyokomi/emoji/v2 v2.2.8
|
github.com/kyokomi/emoji/v2 v2.2.8
|
||||||
|
|
|
||||||
15
go.sum
15
go.sum
|
|
@ -3,13 +3,23 @@ github.com/AlecAivazis/survey/v2 v2.2.8/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
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 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
|
||||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
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=
|
||||||
|
github.com/andygrunwald/go-jira v1.13.0/go.mod h1:jYi4kFDbRPZTJdJOVJO4mpMMIwdB+rcZwSO58DzPd2I=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
|
github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU=
|
||||||
|
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
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/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
|
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/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
|
|
@ -28,6 +38,8 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
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 h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
|
|
@ -38,11 +50,14 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ=
|
||||||
|
github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
|
||||||
github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df h1:Y2l28Jr3vOEeYtxfVbMtVfOdAwuUqWaP9fvNKiBVeXY=
|
github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df h1:Y2l28Jr3vOEeYtxfVbMtVfOdAwuUqWaP9fvNKiBVeXY=
|
||||||
github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df/go.mod h1:pnyouUty/nBr/zm3GYwTIt+qFTLWbdjeLjZmJdzJOu8=
|
github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df/go.mod h1:pnyouUty/nBr/zm3GYwTIt+qFTLWbdjeLjZmJdzJOu8=
|
||||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
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=
|
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-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 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc=
|
||||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
|
|
||||||
36
jira.go
Normal file
36
jira.go
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
package chglog
|
||||||
|
|
||||||
|
import (
|
||||||
|
agjira "github.com/andygrunwald/go-jira"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JiraClient interface {
|
||||||
|
GetJiraIssue(id string) (*agjira.Issue, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type jiraClient struct {
|
||||||
|
username string
|
||||||
|
token string
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJiraClient(config *Config) JiraClient {
|
||||||
|
return jiraClient{
|
||||||
|
username: config.Options.JiraUsername,
|
||||||
|
token: config.Options.JiraToken,
|
||||||
|
url: config.Options.JiraUrl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jira jiraClient) GetJiraIssue(id string) (*agjira.Issue, error) {
|
||||||
|
tp := agjira.BasicAuthTransport{
|
||||||
|
Username: jira.username,
|
||||||
|
Password: jira.token,
|
||||||
|
}
|
||||||
|
client, err := agjira.NewClient(tp.Client(), jira.url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
issue, _, err := client.Issue.Get(id, nil)
|
||||||
|
return issue, err
|
||||||
|
}
|
||||||
42
jira_test.go
Normal file
42
jira_test.go
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package chglog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJira(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
config := &Config {
|
||||||
|
Options: &Options{
|
||||||
|
Processor: nil,
|
||||||
|
NextTag: "",
|
||||||
|
TagFilterPattern: "",
|
||||||
|
CommitFilters: nil,
|
||||||
|
CommitSortBy: "",
|
||||||
|
CommitGroupBy: "",
|
||||||
|
CommitGroupSortBy: "",
|
||||||
|
CommitGroupTitleMaps: nil,
|
||||||
|
HeaderPattern: "",
|
||||||
|
HeaderPatternMaps: nil,
|
||||||
|
IssuePrefix: nil,
|
||||||
|
RefActions: nil,
|
||||||
|
MergePattern: "",
|
||||||
|
MergePatternMaps: nil,
|
||||||
|
RevertPattern: "",
|
||||||
|
RevertPatternMaps: nil,
|
||||||
|
NoteKeywords: nil,
|
||||||
|
JiraUsername: "uuu",
|
||||||
|
JiraToken: "ppp",
|
||||||
|
JiraUrl: "http://jira.com",
|
||||||
|
JiraTypeMaps: nil,
|
||||||
|
JiraIssueDescriptionPattern: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
jira := NewJiraClient(config)
|
||||||
|
issue, err := jira.GetJiraIssue("fake")
|
||||||
|
assert.Nil(issue)
|
||||||
|
assert.Error(err)
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package chglog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package chglog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
1
testdata/gitlog_jira.txt
vendored
Normal file
1
testdata/gitlog_jira.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
@@__CHGLOG__@@HASH:65cf1add9735dcc4810dda3312b0792236c97c4e 65cf1add@@__CHGLOG_DELIMITER__@@AUTHOR:tsuyoshi wada mail@example.com 1514808000@@__CHGLOG_DELIMITER__@@COMMITTER:tsuyoshi wada mail@example.com 1514808000@@__CHGLOG_DELIMITER__@@SUBJECT:[JIRA-1111]: Add new feature #123@@__CHGLOG_DELIMITER__@@BODY: This is body message.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue