mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-23 02:15:12 +00:00
chore(ci): add golangci-lint action and apply linting changes (#120)
BREAKING CHANGE: `JiraIssueId` has been renamed to `JiraIssueID`. This impacts the value for `pattern_maps` in `config.yml`. * chore(ci): add golangci-lint action * chore(lint): address errcheck lint failures * chore(lint): address misspell lint failures * chore(lint): address gocritic lint failures * chore(lint): address golint lint failures * chore(lint): address structcheck lint failures * chore(lint): address gosimple lint failures * chore(lint): address gofmt lint failures * chore(ci): port to official golangci-lint github action * Update golangci configuration for better coverage Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * fix: file is not goimports-ed Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * fix: golint and exported functions comments Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * chore(lint): address gosec G304 warning * chore(lint): address uparam warnings * chore(lint): address scopelint lint failures * fix: cyclomatic complexity Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com> * chore(lint): address prealloc warning, noting that we are warning for now * chore(lint): address govet and errorlint failures * chore: clean up defer logic when checking errors Co-authored-by: Khosrow Moossavi <khos2ow@gmail.com>
This commit is contained in:
parent
2c3d3f400e
commit
ae3382b7c8
37 changed files with 391 additions and 177 deletions
18
.github/workflows/lint.yml
vendored
Normal file
18
.github/workflows/lint.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
name: lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: ['opened', 'synchronize']
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
golangci:
|
||||||
|
name: lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: golangci-lint
|
||||||
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
with:
|
||||||
|
version: v1.38
|
||||||
155
.golangci.yml
Normal file
155
.golangci.yml
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
# https://golangci-lint.run/usage/configuration/
|
||||||
|
run:
|
||||||
|
timeout: 10m
|
||||||
|
deadline: 5m
|
||||||
|
|
||||||
|
tests: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
format: tab
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
govet:
|
||||||
|
# report about shadowed variables
|
||||||
|
check-shadowing: true
|
||||||
|
|
||||||
|
golint:
|
||||||
|
# minimal confidence for issues, default is 0.8
|
||||||
|
min-confidence: 0.8
|
||||||
|
|
||||||
|
gofmt:
|
||||||
|
# simplify code: gofmt with `-s` option, true by default
|
||||||
|
simplify: true
|
||||||
|
|
||||||
|
goimports:
|
||||||
|
# put imports beginning with prefix after 3rd-party packages;
|
||||||
|
# it's a comma-separated list of prefixes
|
||||||
|
local-prefixes: github.com/git-chglog/git-chglog
|
||||||
|
|
||||||
|
gocyclo:
|
||||||
|
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||||
|
min-complexity: 10
|
||||||
|
|
||||||
|
maligned:
|
||||||
|
# print struct with more effective memory layout or not, false by default
|
||||||
|
suggest-new: true
|
||||||
|
|
||||||
|
dupl:
|
||||||
|
# tokens count to trigger issue, 150 by default
|
||||||
|
threshold: 100
|
||||||
|
|
||||||
|
goconst:
|
||||||
|
# minimal length of string constant, 3 by default
|
||||||
|
min-len: 3
|
||||||
|
# minimal occurrences count to trigger, 3 by default
|
||||||
|
min-occurrences: 5
|
||||||
|
|
||||||
|
lll:
|
||||||
|
# tab width in spaces. Default to 1.
|
||||||
|
tab-width: 1
|
||||||
|
|
||||||
|
unused:
|
||||||
|
# treat code as a program (not a library) and report unused exported identifiers; default is false.
|
||||||
|
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
|
||||||
|
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
|
||||||
|
# with golangci-lint call it on a directory with the changed file.
|
||||||
|
check-exported: false
|
||||||
|
|
||||||
|
unparam:
|
||||||
|
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
|
||||||
|
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
|
||||||
|
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
|
||||||
|
# with golangci-lint call it on a directory with the changed file.
|
||||||
|
check-exported: false
|
||||||
|
|
||||||
|
nakedret:
|
||||||
|
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
|
||||||
|
max-func-lines: 30
|
||||||
|
|
||||||
|
prealloc:
|
||||||
|
# XXX: we don't recommend using this linter before doing performance profiling.
|
||||||
|
# For most programs usage of prealloc will be a premature optimization.
|
||||||
|
|
||||||
|
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
|
||||||
|
# True by default.
|
||||||
|
simple: true
|
||||||
|
range-loops: true # Report preallocation suggestions on range loops, true by default
|
||||||
|
for-loops: false # Report preallocation suggestions on for loops, false by default
|
||||||
|
|
||||||
|
gocritic:
|
||||||
|
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks.
|
||||||
|
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
|
||||||
|
enabled-tags:
|
||||||
|
- performance
|
||||||
|
|
||||||
|
settings: # settings passed to gocritic
|
||||||
|
captLocal: # must be valid enabled check name
|
||||||
|
paramsOnly: true
|
||||||
|
rangeValCopy:
|
||||||
|
sizeThreshold: 32
|
||||||
|
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- megacheck
|
||||||
|
- govet
|
||||||
|
- gocyclo
|
||||||
|
- gocritic
|
||||||
|
- interfacer
|
||||||
|
- goconst
|
||||||
|
- goimports
|
||||||
|
- gofmt # We enable this as well as goimports for its simplify mode.
|
||||||
|
- prealloc
|
||||||
|
- golint
|
||||||
|
- unconvert
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- dupl
|
||||||
|
- depguard
|
||||||
|
|
||||||
|
presets:
|
||||||
|
- bugs
|
||||||
|
- unused
|
||||||
|
fast: false
|
||||||
|
|
||||||
|
issues:
|
||||||
|
# Excluding configuration per-path and per-linter
|
||||||
|
exclude-rules:
|
||||||
|
# Exclude some linters from running on tests files.
|
||||||
|
- path: _test(ing)?\.go
|
||||||
|
linters:
|
||||||
|
- gocyclo
|
||||||
|
- errcheck
|
||||||
|
- dupl
|
||||||
|
- gosec
|
||||||
|
- scopelint
|
||||||
|
- unparam
|
||||||
|
|
||||||
|
# These are performance optimisations rather than style issues per se.
|
||||||
|
# They warn when function arguments or range values copy a lot of memory
|
||||||
|
# rather than using a pointer.
|
||||||
|
- text: "(hugeParam|rangeValCopy):"
|
||||||
|
linters:
|
||||||
|
- gocritic
|
||||||
|
|
||||||
|
# Independently from option `exclude` we use default exclude patterns,
|
||||||
|
# it can be disabled by this option. To list all
|
||||||
|
# excluded by default patterns execute `golangci-lint run --help`.
|
||||||
|
# Default value for this option is true.
|
||||||
|
exclude-use-default: false
|
||||||
|
|
||||||
|
# Show only new issues: if there are unstaged changes or untracked files,
|
||||||
|
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
|
||||||
|
# It's a super-useful option for integration of golangci-lint into existing
|
||||||
|
# large codebase. It's not practical to fix all existing issues at the moment
|
||||||
|
# of integration: much better don't allow issues in new code.
|
||||||
|
# Default is false.
|
||||||
|
new: false
|
||||||
|
|
||||||
|
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||||
|
max-per-linter: 0
|
||||||
|
|
||||||
|
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||||
|
max-same-issues: 0
|
||||||
4
Makefile
4
Makefile
|
|
@ -20,3 +20,7 @@ install:
|
||||||
.PHONY: changelog
|
.PHONY: changelog
|
||||||
changelog:
|
changelog:
|
||||||
@git-chglog --next-tag $(tag) $(tag)
|
@git-chglog --next-tag $(tag) $(tag)
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
@golangci-lint run
|
||||||
|
|
|
||||||
|
|
@ -522,7 +522,7 @@ The following is a sample pattern:
|
||||||
pattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$"
|
pattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$"
|
||||||
pattern_maps:
|
pattern_maps:
|
||||||
- Type
|
- Type
|
||||||
- JiraIssueId
|
- JiraIssueID
|
||||||
- Subject
|
- Subject
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -646,6 +646,8 @@ We alway welcome your contributions :clap:
|
||||||
1. Fork (https://github.com/git-chglog/git-chglog) :tada:
|
1. Fork (https://github.com/git-chglog/git-chglog) :tada:
|
||||||
1. Create a feature branch :coffee:
|
1. Create a feature branch :coffee:
|
||||||
1. Run test suite with the `$ make test` command and confirm that it passes :zap:
|
1. Run test suite with the `$ make test` command and confirm that it passes :zap:
|
||||||
|
1. Run linters with the `$ make lint` command and confirm it passes :broom:
|
||||||
|
- The project uses [golangci-lint](https://golangci-lint.run/usage/install/#local-installation)
|
||||||
1. Commit your changes :memo:
|
1. Commit your changes :memo:
|
||||||
1. Rebase your local changes against the `master` branch :bulb:
|
1. Rebase your local changes against the `master` branch :bulb:
|
||||||
1. Create new Pull Request :love_letter:
|
1. Create new Pull Request :love_letter:
|
||||||
|
|
|
||||||
39
chglog.go
39
chglog.go
|
|
@ -5,13 +5,14 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
"github.com/tsuyoshiwada/go-gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options is an option used to process commits
|
// Options is an option used to process commits
|
||||||
|
|
@ -37,7 +38,7 @@ type Options struct {
|
||||||
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
|
JiraUsername string
|
||||||
JiraToken string
|
JiraToken string
|
||||||
JiraUrl string
|
JiraURL string
|
||||||
JiraTypeMaps map[string]string
|
JiraTypeMaps map[string]string
|
||||||
JiraIssueDescriptionPattern string
|
JiraIssueDescriptionPattern string
|
||||||
Paths []string // Path filter
|
Paths []string // Path filter
|
||||||
|
|
@ -138,7 +139,11 @@ func (gen *Generator) Generate(w io.Writer, query string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer back()
|
defer func() {
|
||||||
|
if err = back(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
tags, first, err := gen.getTags(query)
|
tags, first, err := gen.getTags(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -269,7 +274,7 @@ func (gen *Generator) getTags(query string) ([]*Tag, string, error) {
|
||||||
|
|
||||||
// Assign the date with `readVersions()`
|
// Assign the date with `readVersions()`
|
||||||
tags = append([]*Tag{
|
tags = append([]*Tag{
|
||||||
&Tag{
|
{
|
||||||
Name: next,
|
Name: next,
|
||||||
Subject: next,
|
Subject: next,
|
||||||
Previous: previous,
|
Previous: previous,
|
||||||
|
|
@ -318,30 +323,18 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve
|
||||||
"datetime": func(layout string, input time.Time) string {
|
"datetime": func(layout string, input time.Time) string {
|
||||||
return input.Format(layout)
|
return input.Format(layout)
|
||||||
},
|
},
|
||||||
// check whether substs is withing s
|
// check whether substr is within s
|
||||||
"contains": func(s, substr string) bool {
|
"contains": strings.Contains,
|
||||||
return strings.Contains(s, substr)
|
|
||||||
},
|
|
||||||
// check whether s begins with prefix
|
// check whether s begins with prefix
|
||||||
"hasPrefix": func(s, prefix string) bool {
|
"hasPrefix": strings.HasPrefix,
|
||||||
return strings.HasPrefix(s, prefix)
|
|
||||||
},
|
|
||||||
// check whether s ends with suffix
|
// check whether s ends with suffix
|
||||||
"hasSuffix": func(s, suffix string) bool {
|
"hasSuffix": strings.HasSuffix,
|
||||||
return strings.HasSuffix(s, suffix)
|
|
||||||
},
|
|
||||||
// replace the first n instances of old with new
|
// replace the first n instances of old with new
|
||||||
"replace": func(s, old, new string, n int) string {
|
"replace": strings.Replace,
|
||||||
return strings.Replace(s, old, new, n)
|
|
||||||
},
|
|
||||||
// lower case a string
|
// lower case a string
|
||||||
"lower": func(s string) string {
|
"lower": strings.ToLower,
|
||||||
return strings.ToLower(s)
|
|
||||||
},
|
|
||||||
// upper case a string
|
// upper case a string
|
||||||
"upper": func(s string) string {
|
"upper": strings.ToUpper,
|
||||||
return strings.ToUpper(s)
|
|
||||||
},
|
|
||||||
// upper case the first character of a string
|
// upper case the first character of a string
|
||||||
"upperFirst": func(s string) string {
|
"upperFirst": func(s string) string {
|
||||||
if len(s) > 0 {
|
if len(s) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -32,17 +32,17 @@ func TestMain(m *testing.M) {
|
||||||
func setup(dir string, setupRepo func(commitFunc, tagFunc, gitcmd.Client)) {
|
func setup(dir string, setupRepo func(commitFunc, tagFunc, gitcmd.Client)) {
|
||||||
testDir := filepath.Join(cwd, testRepoRoot, dir)
|
testDir := filepath.Join(cwd, testRepoRoot, dir)
|
||||||
|
|
||||||
os.RemoveAll(testDir)
|
_ = os.RemoveAll(testDir)
|
||||||
os.MkdirAll(testDir, os.ModePerm)
|
_ = os.MkdirAll(testDir, os.ModePerm)
|
||||||
os.Chdir(testDir)
|
_ = os.Chdir(testDir)
|
||||||
|
|
||||||
loc, _ := time.LoadLocation("UTC")
|
loc, _ := time.LoadLocation("UTC")
|
||||||
time.Local = loc
|
time.Local = loc
|
||||||
|
|
||||||
git := gitcmd.New(nil)
|
git := gitcmd.New(nil)
|
||||||
git.Exec("init")
|
_, _ = git.Exec("init")
|
||||||
git.Exec("config", "user.name", "test_user")
|
_, _ = git.Exec("config", "user.name", "test_user")
|
||||||
git.Exec("config", "user.email", "test@example.com")
|
_, _ = git.Exec("config", "user.email", "test@example.com")
|
||||||
|
|
||||||
var commit = func(date, subject, body string) {
|
var commit = func(date, subject, body string) {
|
||||||
msg := subject
|
msg := subject
|
||||||
|
|
@ -51,21 +51,21 @@ func setup(dir string, setupRepo func(commitFunc, tagFunc, gitcmd.Client)) {
|
||||||
}
|
}
|
||||||
t, _ := time.Parse(internalTimeFormat, date)
|
t, _ := time.Parse(internalTimeFormat, date)
|
||||||
d := t.Format("Mon Jan 2 15:04:05 2006 +0000")
|
d := t.Format("Mon Jan 2 15:04:05 2006 +0000")
|
||||||
git.Exec("commit", "--allow-empty", "--date", d, "-m", msg)
|
_, _ = git.Exec("commit", "--allow-empty", "--date", d, "-m", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tag = func(name string) {
|
var tag = func(name string) {
|
||||||
git.Exec("tag", name)
|
_, _ = git.Exec("tag", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupRepo(commit, tag, git)
|
setupRepo(commit, tag, git)
|
||||||
|
|
||||||
os.Chdir(cwd)
|
_ = os.Chdir(cwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanup() {
|
func cleanup() {
|
||||||
os.Chdir(cwd)
|
_ = os.Chdir(cwd)
|
||||||
os.RemoveAll(filepath.Join(cwd, testRepoRoot))
|
_ = os.RemoveAll(filepath.Join(cwd, testRepoRoot))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGeneratorNotFoundTags(t *testing.T) {
|
func TestGeneratorNotFoundTags(t *testing.T) {
|
||||||
|
|
@ -193,7 +193,7 @@ func TestGeneratorWithTypeScopeSubject(t *testing.T) {
|
||||||
tag("1.1.0")
|
tag("1.1.0")
|
||||||
|
|
||||||
commit("2018-01-03 00:00:00", "feat(context): Online breaking change", "BREAKING CHANGE: Online breaking change message.")
|
commit("2018-01-03 00:00:00", "feat(context): Online breaking change", "BREAKING CHANGE: Online breaking change message.")
|
||||||
commit("2018-01-03 00:01:00", "feat(router): Muliple breaking change", `This is body,
|
commit("2018-01-03 00:01:00", "feat(router): Multiple breaking change", `This is body,
|
||||||
|
|
||||||
BREAKING CHANGE:
|
BREAKING CHANGE:
|
||||||
Multiple
|
Multiple
|
||||||
|
|
@ -216,7 +216,7 @@ change message.`)
|
||||||
},
|
},
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
CommitFilters: map[string][]string{
|
CommitFilters: map[string][]string{
|
||||||
"Type": []string{
|
"Type": {
|
||||||
"feat",
|
"feat",
|
||||||
"fix",
|
"fix",
|
||||||
},
|
},
|
||||||
|
|
@ -256,7 +256,7 @@ change message.`)
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
output := strings.Replace(strings.TrimSpace(buf.String()), "\r\n", "\n", -1)
|
output := strings.ReplaceAll(strings.TrimSpace(buf.String()), "\r\n", "\n")
|
||||||
|
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(`<a name="unreleased"></a>
|
assert.Equal(`<a name="unreleased"></a>
|
||||||
|
|
@ -270,7 +270,7 @@ change message.`)
|
||||||
## [2.0.0-beta.0] - 2018-01-03
|
## [2.0.0-beta.0] - 2018-01-03
|
||||||
### Features
|
### Features
|
||||||
- **context:** Online breaking change
|
- **context:** Online breaking change
|
||||||
- **router:** Muliple breaking change
|
- **router:** Multiple breaking change
|
||||||
|
|
||||||
### BREAKING CHANGE
|
### BREAKING CHANGE
|
||||||
|
|
||||||
|
|
@ -331,7 +331,7 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
NextTag: "3.0.0",
|
NextTag: "3.0.0",
|
||||||
CommitFilters: map[string][]string{
|
CommitFilters: map[string][]string{
|
||||||
"Type": []string{
|
"Type": {
|
||||||
"feat",
|
"feat",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -352,7 +352,7 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
err := gen.Generate(buf, "")
|
err := gen.Generate(buf, "")
|
||||||
output := strings.Replace(strings.TrimSpace(buf.String()), "\r\n", "\n", -1)
|
output := strings.ReplaceAll(strings.TrimSpace(buf.String()), "\r\n", "\n")
|
||||||
|
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(`<a name="unreleased"></a>
|
assert.Equal(`<a name="unreleased"></a>
|
||||||
|
|
@ -383,7 +383,7 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
||||||
|
|
||||||
buf = &bytes.Buffer{}
|
buf = &bytes.Buffer{}
|
||||||
err = gen.Generate(buf, "3.0.0")
|
err = gen.Generate(buf, "3.0.0")
|
||||||
output = strings.Replace(strings.TrimSpace(buf.String()), "\r\n", "\n", -1)
|
output = strings.ReplaceAll(strings.TrimSpace(buf.String()), "\r\n", "\n")
|
||||||
|
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(`<a name="unreleased"></a>
|
assert.Equal(`<a name="unreleased"></a>
|
||||||
|
|
@ -424,7 +424,7 @@ func TestGeneratorWithTagFiler(t *testing.T) {
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
TagFilterPattern: "^v",
|
TagFilterPattern: "^v",
|
||||||
CommitFilters: map[string][]string{
|
CommitFilters: map[string][]string{
|
||||||
"Type": []string{
|
"Type": {
|
||||||
"feat",
|
"feat",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
|
||||||
chglog "github.com/git-chglog/git-chglog"
|
chglog "github.com/git-chglog/git-chglog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,9 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
chglog "github.com/git-chglog/git-chglog"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
chglog "github.com/git-chglog/git-chglog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCLIForStdout(t *testing.T) {
|
func TestCLIForStdout(t *testing.T) {
|
||||||
|
|
@ -36,7 +37,7 @@ func TestCLIForStdout(t *testing.T) {
|
||||||
if config.Bin != "/custom/bin/git" {
|
if config.Bin != "/custom/bin/git" {
|
||||||
return errors.New("")
|
return errors.New("")
|
||||||
}
|
}
|
||||||
w.Write([]byte("success!!"))
|
_, _ = w.Write([]byte("success!!"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +105,7 @@ func TestCLIForFile(t *testing.T) {
|
||||||
if filepath.ToSlash(config.Bin) != "/custom/bin/git" {
|
if filepath.ToSlash(config.Bin) != "/custom/bin/git" {
|
||||||
return errors.New("")
|
return errors.New("")
|
||||||
}
|
}
|
||||||
w.Write([]byte("success!!"))
|
_, _ = w.Write([]byte("success!!"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
chglog "github.com/git-chglog/git-chglog"
|
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
|
|
||||||
|
chglog "github.com/git-chglog/git-chglog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Info ...
|
// Info ...
|
||||||
|
|
@ -49,6 +50,7 @@ type NoteOptions struct {
|
||||||
Keywords []string `yaml:"keywords"`
|
Keywords []string `yaml:"keywords"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JiraClientInfoOptions ...
|
||||||
type JiraClientInfoOptions struct {
|
type JiraClientInfoOptions struct {
|
||||||
Username string `yaml:"username"`
|
Username string `yaml:"username"`
|
||||||
Token string `yaml:"token"`
|
Token string `yaml:"token"`
|
||||||
|
|
@ -286,7 +288,7 @@ func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
||||||
Template: orValue(ctx.Template, config.Template),
|
Template: orValue(ctx.Template, config.Template),
|
||||||
Info: &chglog.Info{
|
Info: &chglog.Info{
|
||||||
Title: info.Title,
|
Title: info.Title,
|
||||||
RepositoryURL: orValue(ctx.RepositoryUrl, info.RepositoryURL),
|
RepositoryURL: orValue(ctx.RepositoryURL, info.RepositoryURL),
|
||||||
},
|
},
|
||||||
Options: &chglog.Options{
|
Options: &chglog.Options{
|
||||||
NextTag: ctx.NextTag,
|
NextTag: ctx.NextTag,
|
||||||
|
|
@ -309,7 +311,7 @@ func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
||||||
NoteKeywords: opts.Notes.Keywords,
|
NoteKeywords: opts.Notes.Keywords,
|
||||||
JiraUsername: orValue(ctx.JiraUsername, opts.Jira.ClintInfo.Username),
|
JiraUsername: orValue(ctx.JiraUsername, opts.Jira.ClintInfo.Username),
|
||||||
JiraToken: orValue(ctx.JiraToken, opts.Jira.ClintInfo.Token),
|
JiraToken: orValue(ctx.JiraToken, opts.Jira.ClintInfo.Token),
|
||||||
JiraUrl: orValue(ctx.JiraUrl, opts.Jira.ClintInfo.URL),
|
JiraURL: orValue(ctx.JiraURL, opts.Jira.ClintInfo.URL),
|
||||||
JiraTypeMaps: opts.Jira.Issue.TypeMaps,
|
JiraTypeMaps: opts.Jira.Issue.TypeMaps,
|
||||||
JiraIssueDescriptionPattern: opts.Jira.Issue.DescriptionPattern,
|
JiraIssueDescriptionPattern: opts.Jira.Issue.DescriptionPattern,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigLoader ...
|
// ConfigLoader ...
|
||||||
|
|
@ -20,7 +21,8 @@ func NewConfigLoader() ConfigLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (loader *configLoaderImpl) Load(path string) (*Config, error) {
|
func (loader *configLoaderImpl) Load(path string) (*Config, error) {
|
||||||
bytes, err := ioutil.ReadFile(path)
|
fp := filepath.Clean(path)
|
||||||
|
bytes, err := ioutil.ReadFile(fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ type CLIContext struct {
|
||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
ConfigPath string
|
ConfigPath string
|
||||||
Template string
|
Template string
|
||||||
RepositoryUrl string
|
RepositoryURL string
|
||||||
OutputPath string
|
OutputPath string
|
||||||
Silent bool
|
Silent bool
|
||||||
NoColor bool
|
NoColor bool
|
||||||
|
|
@ -22,7 +22,7 @@ type CLIContext struct {
|
||||||
TagFilterPattern string
|
TagFilterPattern string
|
||||||
JiraUsername string
|
JiraUsername string
|
||||||
JiraToken string
|
JiraToken string
|
||||||
JiraUrl string
|
JiraURL string
|
||||||
Paths []string
|
Paths []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func (t *customTemplateBuilderImpl) Build(ans *Answer) (string, error) {
|
||||||
tpl += t.versionHeader(ans.Style, ans.Template)
|
tpl += t.versionHeader(ans.Style, ans.Template)
|
||||||
|
|
||||||
// commits
|
// commits
|
||||||
tpl += t.commits(ans.Template, ans.CommitMessageFormat)
|
tpl += t.commits(ans.CommitMessageFormat)
|
||||||
|
|
||||||
// revert
|
// revert
|
||||||
if ans.IncludeReverts {
|
if ans.IncludeReverts {
|
||||||
|
|
@ -75,7 +75,7 @@ func (*customTemplateBuilderImpl) versionHeader(style, template string) string {
|
||||||
return tpl
|
return tpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*customTemplateBuilderImpl) commits(template, format string) string {
|
func (*customTemplateBuilderImpl) commits(format string) string {
|
||||||
var (
|
var (
|
||||||
header string
|
header string
|
||||||
body string
|
body string
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,16 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/git-chglog/git-chglog"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
|
||||||
|
chglog "github.com/git-chglog/git-chglog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initializer ...
|
// Initializer ...
|
||||||
type Initializer struct {
|
type Initializer struct {
|
||||||
ctx *InitContext
|
ctx *InitContext
|
||||||
client gitcmd.Client
|
|
||||||
fs FileSystem
|
fs FileSystem
|
||||||
logger *chglog.Logger
|
logger *chglog.Logger
|
||||||
questioner Questioner
|
questioner Questioner
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,17 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/mattn/go-colorable"
|
"github.com/mattn/go-colorable"
|
||||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
"github.com/tsuyoshiwada/go-gitcmd"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CreateApp creates and initializes CLI application
|
||||||
|
// with description, flags, version, etc.
|
||||||
func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||||
ttl := color.New(color.FgYellow).SprintFunc()
|
ttl := color.New(color.FgYellow).SprintFunc()
|
||||||
|
|
||||||
|
|
@ -182,6 +185,8 @@ func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AppAction is a callback function to create initializer
|
||||||
|
// and CLIContext and ultimately run the application.
|
||||||
func AppAction(c *cli.Context) error {
|
func AppAction(c *cli.Context) error {
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -219,7 +224,7 @@ func AppAction(c *cli.Context) error {
|
||||||
Stderr: colorable.NewColorableStderr(),
|
Stderr: colorable.NewColorableStderr(),
|
||||||
ConfigPath: c.String("config"),
|
ConfigPath: c.String("config"),
|
||||||
Template: c.String("template"),
|
Template: c.String("template"),
|
||||||
RepositoryUrl: c.String("repository-url"),
|
RepositoryURL: c.String("repository-url"),
|
||||||
OutputPath: c.String("output"),
|
OutputPath: c.String("output"),
|
||||||
Silent: c.Bool("silent"),
|
Silent: c.Bool("silent"),
|
||||||
NoColor: c.Bool("no-color"),
|
NoColor: c.Bool("no-color"),
|
||||||
|
|
@ -230,7 +235,7 @@ func AppAction(c *cli.Context) error {
|
||||||
TagFilterPattern: c.String("tag-filter-pattern"),
|
TagFilterPattern: c.String("tag-filter-pattern"),
|
||||||
JiraUsername: c.String("jira-username"),
|
JiraUsername: c.String("jira-username"),
|
||||||
JiraToken: c.String("jira-token"),
|
JiraToken: c.String("jira-token"),
|
||||||
JiraUrl: c.String("jira-url"),
|
JiraURL: c.String("jira-url"),
|
||||||
Paths: c.StringSlice("path"),
|
Paths: c.StringSlice("path"),
|
||||||
},
|
},
|
||||||
fs,
|
fs,
|
||||||
|
|
@ -245,5 +250,8 @@ func AppAction(c *cli.Context) error {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := CreateApp(AppAction)
|
app := CreateApp(AppAction)
|
||||||
app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var gAssert *assert.Assertions
|
var gAssert *assert.Assertions
|
||||||
|
|
||||||
func mock_app_action(c *cli.Context) error {
|
func mockAppAction(c *cli.Context) error {
|
||||||
assert := gAssert
|
assert := gAssert
|
||||||
assert.Equal("c.yml", c.String("config"))
|
assert.Equal("c.yml", c.String("config"))
|
||||||
assert.Equal("^v", c.String("tag-filter-pattern"))
|
assert.Equal("^v", c.String("tag-filter-pattern"))
|
||||||
|
|
@ -25,7 +27,7 @@ func TestCreateApp(t *testing.T) {
|
||||||
assert.True(true)
|
assert.True(true)
|
||||||
gAssert = assert
|
gAssert = assert
|
||||||
|
|
||||||
app := CreateApp(mock_app_action)
|
app := CreateApp(mockAppAction)
|
||||||
args := []string{
|
args := []string{
|
||||||
"git-chglog",
|
"git-chglog",
|
||||||
"--silent",
|
"--silent",
|
||||||
|
|
@ -36,5 +38,8 @@ func TestCreateApp(t *testing.T) {
|
||||||
"--next-tag", "v5",
|
"--next-tag", "v5",
|
||||||
"--tag-filter-pattern", "^v",
|
"--tag-filter-pattern", "^v",
|
||||||
}
|
}
|
||||||
app.Run(args)
|
err := app.Run(args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
chglog "github.com/git-chglog/git-chglog"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
chglog "github.com/git-chglog/git-chglog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProcessorFactory(t *testing.T) {
|
func TestProcessorFactory(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
survey "github.com/AlecAivazis/survey/v2"
|
"github.com/tsuyoshiwada/go-gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Answer ...
|
// Answer ...
|
||||||
|
|
@ -52,11 +52,12 @@ func (q *questionerImpl) Ask() (*Answer, error) {
|
||||||
t := q.fs.Exists(tpl)
|
t := q.fs.Exists(tpl)
|
||||||
msg := ""
|
msg := ""
|
||||||
|
|
||||||
if c && t {
|
switch {
|
||||||
|
case c && t:
|
||||||
msg = fmt.Sprintf("\"%s\" and \"%s\" already exists. Do you want to overwrite?", config, tpl)
|
msg = fmt.Sprintf("\"%s\" and \"%s\" already exists. Do you want to overwrite?", config, tpl)
|
||||||
} else if c {
|
case c:
|
||||||
msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", config)
|
msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", config)
|
||||||
} else if t {
|
case t:
|
||||||
msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", tpl)
|
msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", tpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var reSSH = regexp.MustCompile("^\\w+@([\\w\\.\\-]+):([\\w\\.\\-]+)\\/([\\w\\.\\-]+)$")
|
var reSSH = regexp.MustCompile(`^\w+@([\w\.\-]+):([\w\.\-]+)\/([\w\.\-]+)$`)
|
||||||
|
|
||||||
func remoteOriginURLToHTTP(rawurl string) string {
|
func remoteOriginURLToHTTP(rawurl string) string {
|
||||||
if rawurl == "" {
|
if rawurl == "" {
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func (f *CommitMessageFormat) PatternMapString() string {
|
||||||
return fmt.Sprintf("\n%s", strings.Join(arr, "\n"))
|
return fmt.Sprintf("\n%s", strings.Join(arr, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterTypeString ...
|
// FilterTypesString ...
|
||||||
func (f *CommitMessageFormat) FilterTypesString() string {
|
func (f *CommitMessageFormat) FilterTypesString() string {
|
||||||
if len(f.typeSamples) == 0 {
|
if len(f.typeSamples) == 0 {
|
||||||
return " []"
|
return " []"
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,11 @@ func (e *commitExtractor) commitGroupTitle(commit *Commit) (string, string) {
|
||||||
return raw, ttl
|
return raw, ttl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) {
|
func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) { //nolint:gocyclo
|
||||||
|
// NOTE(khos2ow): this function is over our cyclomatic complexity goal.
|
||||||
|
// Be wary when adding branches, and look for functionality that could
|
||||||
|
// be reasonably moved into an injected dependency.
|
||||||
|
|
||||||
order := make(map[string]int)
|
order := make(map[string]int)
|
||||||
if e.opts.CommitGroupSortBy == "Custom" {
|
if e.opts.CommitGroupSortBy == "Custom" {
|
||||||
for i, t := range e.opts.CommitGroupTitleOrder {
|
for i, t := range e.opts.CommitGroupTitleOrder {
|
||||||
|
|
@ -136,6 +140,9 @@ func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// groups
|
// groups
|
||||||
|
// TODO(khos2ow): move the inline sort function to
|
||||||
|
// conceret implementation of sort.Interface in order
|
||||||
|
// to reduce cyclomatic complaxity.
|
||||||
sort.Slice(groups, func(i, j int) bool {
|
sort.Slice(groups, func(i, j int) bool {
|
||||||
if e.opts.CommitGroupSortBy == "Custom" {
|
if e.opts.CommitGroupSortBy == "Custom" {
|
||||||
return order[groups[i].RawTitle] < order[groups[j].RawTitle]
|
return order[groups[i].RawTitle] < order[groups[j].RawTitle]
|
||||||
|
|
@ -165,6 +172,11 @@ func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) {
|
||||||
|
|
||||||
// commits
|
// commits
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
|
group := group // pin group to avoid potential bugs with passing group to lower functions
|
||||||
|
|
||||||
|
// TODO(khos2ow): move the inline sort function to
|
||||||
|
// conceret implementation of sort.Interface in order
|
||||||
|
// to reduce cyclomatic complaxity.
|
||||||
sort.Slice(group.Commits, func(i, j int) bool {
|
sort.Slice(group.Commits, func(i, j int) bool {
|
||||||
var (
|
var (
|
||||||
a, b interface{}
|
a, b interface{}
|
||||||
|
|
@ -198,6 +210,7 @@ func (e *commitExtractor) sortNoteGroups(groups []*NoteGroup) {
|
||||||
|
|
||||||
// notes
|
// notes
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
|
group := group // pin group to avoid potential bugs with passing group to lower functions
|
||||||
sort.Slice(group.Notes, func(i, j int) bool {
|
sort.Slice(group.Notes, func(i, j int) bool {
|
||||||
return strings.ToLower(group.Notes[i].Title) < strings.ToLower(group.Notes[j].Title)
|
return strings.ToLower(group.Notes[i].Title) < strings.ToLower(group.Notes[j].Title)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
|
|
||||||
fixtures := []*Commit{
|
fixtures := []*Commit{
|
||||||
// [0]
|
// [0]
|
||||||
&Commit{
|
{
|
||||||
Type: "foo",
|
Type: "foo",
|
||||||
Scope: "c",
|
Scope: "c",
|
||||||
Header: "1",
|
Header: "1",
|
||||||
Notes: []*Note{},
|
Notes: []*Note{},
|
||||||
},
|
},
|
||||||
// [1]
|
// [1]
|
||||||
&Commit{
|
{
|
||||||
Type: "foo",
|
Type: "foo",
|
||||||
Scope: "b",
|
Scope: "b",
|
||||||
Header: "2",
|
Header: "2",
|
||||||
|
|
@ -37,7 +37,7 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// [2]
|
// [2]
|
||||||
&Commit{
|
{
|
||||||
Type: "bar",
|
Type: "bar",
|
||||||
Scope: "d",
|
Scope: "d",
|
||||||
Header: "3",
|
Header: "3",
|
||||||
|
|
@ -47,7 +47,7 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// [3]
|
// [3]
|
||||||
&Commit{
|
{
|
||||||
Type: "foo",
|
Type: "foo",
|
||||||
Scope: "a",
|
Scope: "a",
|
||||||
Header: "4",
|
Header: "4",
|
||||||
|
|
@ -56,7 +56,7 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// [4]
|
// [4]
|
||||||
&Commit{
|
{
|
||||||
Type: "",
|
Type: "",
|
||||||
Scope: "",
|
Scope: "",
|
||||||
Header: "Merge1",
|
Header: "Merge1",
|
||||||
|
|
@ -67,7 +67,7 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// [5]
|
// [5]
|
||||||
&Commit{
|
{
|
||||||
Type: "",
|
Type: "",
|
||||||
Scope: "",
|
Scope: "",
|
||||||
Header: "Revert1",
|
Header: "Revert1",
|
||||||
|
|
@ -81,14 +81,14 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
commitGroups, mergeCommits, revertCommits, noteGroups := extractor.Extract(fixtures)
|
commitGroups, mergeCommits, revertCommits, noteGroups := extractor.Extract(fixtures)
|
||||||
|
|
||||||
assert.Equal([]*CommitGroup{
|
assert.Equal([]*CommitGroup{
|
||||||
&CommitGroup{
|
{
|
||||||
RawTitle: "bar",
|
RawTitle: "bar",
|
||||||
Title: "BAR",
|
Title: "BAR",
|
||||||
Commits: []*Commit{
|
Commits: []*Commit{
|
||||||
fixtures[2],
|
fixtures[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&CommitGroup{
|
{
|
||||||
RawTitle: "foo",
|
RawTitle: "foo",
|
||||||
Title: "Foo",
|
Title: "Foo",
|
||||||
Commits: []*Commit{
|
Commits: []*Commit{
|
||||||
|
|
@ -108,26 +108,26 @@ func TestCommitExtractor(t *testing.T) {
|
||||||
}, revertCommits)
|
}, revertCommits)
|
||||||
|
|
||||||
assert.Equal([]*NoteGroup{
|
assert.Equal([]*NoteGroup{
|
||||||
&NoteGroup{
|
{
|
||||||
Title: "note1-title",
|
Title: "note1-title",
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
fixtures[1].Notes[0],
|
fixtures[1].Notes[0],
|
||||||
fixtures[2].Notes[0],
|
fixtures[2].Notes[0],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NoteGroup{
|
{
|
||||||
Title: "note2-title",
|
Title: "note2-title",
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
fixtures[1].Notes[1],
|
fixtures[1].Notes[1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NoteGroup{
|
{
|
||||||
Title: "note3-title",
|
Title: "note3-title",
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
fixtures[2].Notes[1],
|
fixtures[2].Notes[1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&NoteGroup{
|
{
|
||||||
Title: "note4-title",
|
Title: "note4-title",
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
fixtures[3].Notes[0],
|
fixtures[3].Notes[0],
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func commitFilter(commits []*Commit, filters map[string][]string, noCaseSensitive bool) []*Commit {
|
func commitFilter(commits []*Commit, filters map[string][]string, noCaseSensitive bool) []*Commit { //nolint:gocyclo
|
||||||
|
// NOTE(khos2ow): this function is over our cyclomatic complexity goal.
|
||||||
|
// Be wary when adding branches, and look for functionality that could
|
||||||
|
// be reasonably moved into an injected dependency.
|
||||||
|
|
||||||
res := []*Commit{}
|
res := []*Commit{}
|
||||||
|
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,27 @@ func TestCommitFilter(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fixtures := []*Commit{
|
fixtures := []*Commit{
|
||||||
&Commit{
|
{
|
||||||
Type: "foo",
|
Type: "foo",
|
||||||
Scope: "hoge",
|
Scope: "hoge",
|
||||||
Subject: "1",
|
Subject: "1",
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Type: "foo",
|
Type: "foo",
|
||||||
Scope: "fuga",
|
Scope: "fuga",
|
||||||
Subject: "2",
|
Subject: "2",
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Type: "bar",
|
Type: "bar",
|
||||||
Scope: "hoge",
|
Scope: "hoge",
|
||||||
Subject: "3",
|
Subject: "3",
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Type: "bar",
|
Type: "bar",
|
||||||
Scope: "fuga",
|
Scope: "fuga",
|
||||||
Subject: "4",
|
Subject: "4",
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Type: "Bar",
|
Type: "Bar",
|
||||||
Scope: "hogera",
|
Scope: "hogera",
|
||||||
Subject: "5",
|
Subject: "5",
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func newCommitParser(logger *Logger, client gitcmd.Client, jiraClient JiraClient
|
||||||
reRef: regexp.MustCompile("(?i)(" + joinedRefActions + ")\\s?([\\w/\\.\\-]+)?(?:" + joinedIssuePrefix + ")(\\d+)"),
|
reRef: regexp.MustCompile("(?i)(" + joinedRefActions + ")\\s?([\\w/\\.\\-]+)?(?:" + joinedIssuePrefix + ")(\\d+)"),
|
||||||
reIssue: regexp.MustCompile("(?:" + joinedIssuePrefix + ")(\\d+)"),
|
reIssue: regexp.MustCompile("(?:" + joinedIssuePrefix + ")(\\d+)"),
|
||||||
reNotes: regexp.MustCompile("^(?i)\\s*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
|
reNotes: regexp.MustCompile("^(?i)\\s*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
|
||||||
reMention: regexp.MustCompile("@([\\w-]+)"),
|
reMention: regexp.MustCompile(`@([\w-]+)`),
|
||||||
reJiraIssueDescription: regexp.MustCompile(opts.JiraIssueDescriptionPattern),
|
reJiraIssueDescription: regexp.MustCompile(opts.JiraIssueDescriptionPattern),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,8 +223,8 @@ func (p *commitParser) processHeader(commit *Commit, input string) {
|
||||||
commit.Mentions = p.parseMentions(input)
|
commit.Mentions = p.parseMentions(input)
|
||||||
|
|
||||||
// Jira
|
// Jira
|
||||||
if commit.JiraIssueId != "" {
|
if commit.JiraIssueID != "" {
|
||||||
p.processJiraIssue(commit, commit.JiraIssueId)
|
p.processJiraIssue(commit, commit.JiraIssueID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,10 +364,10 @@ func (p *commitParser) uniqMentions(mentions []string) []string {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *commitParser) processJiraIssue(commit *Commit, issueId string) {
|
func (p *commitParser) processJiraIssue(commit *Commit, issueID string) {
|
||||||
issue, err := p.jiraClient.GetJiraIssue(commit.JiraIssueId)
|
issue, err := p.jiraClient.GetJiraIssue(commit.JiraIssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.logger.Error(fmt.Sprintf("Failed to parse Jira story %s: %s\n", issueId, err))
|
p.logger.Error(fmt.Sprintf("Failed to parse Jira story %s: %s\n", issueID, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
commit.Type = p.config.Options.JiraTypeMaps[issue.Fields.Type.Name]
|
commit.Type = p.config.Options.JiraTypeMaps[issue.Fields.Type.Name]
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func TestCommitParserParse(t *testing.T) {
|
||||||
mock, nil, &Config{
|
mock, nil, &Config{
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
CommitFilters: map[string][]string{
|
CommitFilters: map[string][]string{
|
||||||
"Type": []string{
|
"Type": {
|
||||||
"feat",
|
"feat",
|
||||||
"fix",
|
"fix",
|
||||||
"perf",
|
"perf",
|
||||||
|
|
@ -79,7 +79,7 @@ func TestCommitParserParse(t *testing.T) {
|
||||||
commits, err := parser.Parse("HEAD")
|
commits, err := parser.Parse("HEAD")
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal([]*Commit{
|
assert.Equal([]*Commit{
|
||||||
&Commit{
|
{
|
||||||
Hash: &Hash{
|
Hash: &Hash{
|
||||||
Long: "65cf1add9735dcc4810dda3312b0792236c97c4e",
|
Long: "65cf1add9735dcc4810dda3312b0792236c97c4e",
|
||||||
Short: "65cf1add",
|
Short: "65cf1add",
|
||||||
|
|
@ -97,7 +97,7 @@ func TestCommitParserParse(t *testing.T) {
|
||||||
Merge: nil,
|
Merge: nil,
|
||||||
Revert: nil,
|
Revert: nil,
|
||||||
Refs: []*Ref{
|
Refs: []*Ref{
|
||||||
&Ref{
|
{
|
||||||
Action: "",
|
Action: "",
|
||||||
Ref: "123",
|
Ref: "123",
|
||||||
Source: "",
|
Source: "",
|
||||||
|
|
@ -111,7 +111,7 @@ func TestCommitParserParse(t *testing.T) {
|
||||||
Subject: "Add new feature #123",
|
Subject: "Add new feature #123",
|
||||||
Body: "",
|
Body: "",
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Hash: &Hash{
|
Hash: &Hash{
|
||||||
Long: "14ef0b6d386c5432af9292eab3c8314fa3001bc7",
|
Long: "14ef0b6d386c5432af9292eab3c8314fa3001bc7",
|
||||||
Short: "14ef0b6d",
|
Short: "14ef0b6d",
|
||||||
|
|
@ -132,24 +132,24 @@ func TestCommitParserParse(t *testing.T) {
|
||||||
},
|
},
|
||||||
Revert: nil,
|
Revert: nil,
|
||||||
Refs: []*Ref{
|
Refs: []*Ref{
|
||||||
&Ref{
|
{
|
||||||
Action: "",
|
Action: "",
|
||||||
Ref: "3",
|
Ref: "3",
|
||||||
Source: "",
|
Source: "",
|
||||||
},
|
},
|
||||||
&Ref{
|
{
|
||||||
Action: "Fixes",
|
Action: "Fixes",
|
||||||
Ref: "3",
|
Ref: "3",
|
||||||
Source: "",
|
Source: "",
|
||||||
},
|
},
|
||||||
&Ref{
|
{
|
||||||
Action: "Closes",
|
Action: "Closes",
|
||||||
Ref: "1",
|
Ref: "1",
|
||||||
Source: "",
|
Source: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Title: "BREAKING CHANGE",
|
Title: "BREAKING CHANGE",
|
||||||
Body: "This is breaking point message.",
|
Body: "This is breaking point message.",
|
||||||
},
|
},
|
||||||
|
|
@ -167,7 +167,7 @@ Closes #1
|
||||||
|
|
||||||
BREAKING CHANGE: This is breaking point message.`,
|
BREAKING CHANGE: This is breaking point message.`,
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Hash: &Hash{
|
Hash: &Hash{
|
||||||
Long: "809a8280ffd0dadb0f4e7ba9fc835e63c37d6af6",
|
Long: "809a8280ffd0dadb0f4e7ba9fc835e63c37d6af6",
|
||||||
Short: "809a8280",
|
Short: "809a8280",
|
||||||
|
|
@ -201,7 +201,7 @@ BREAKING CHANGE: This is breaking point message.`,
|
||||||
@hogefuga
|
@hogefuga
|
||||||
@FooBarBaz`,
|
@FooBarBaz`,
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Hash: &Hash{
|
Hash: &Hash{
|
||||||
Long: "74824d6bd1470b901ec7123d13a76a1b8938d8d0",
|
Long: "74824d6bd1470b901ec7123d13a76a1b8938d8d0",
|
||||||
Short: "74824d6b",
|
Short: "74824d6b",
|
||||||
|
|
@ -219,19 +219,19 @@ BREAKING CHANGE: This is breaking point message.`,
|
||||||
Merge: nil,
|
Merge: nil,
|
||||||
Revert: nil,
|
Revert: nil,
|
||||||
Refs: []*Ref{
|
Refs: []*Ref{
|
||||||
&Ref{
|
{
|
||||||
Action: "Fixes",
|
Action: "Fixes",
|
||||||
Ref: "123",
|
Ref: "123",
|
||||||
Source: "",
|
Source: "",
|
||||||
},
|
},
|
||||||
&Ref{
|
{
|
||||||
Action: "Closes",
|
Action: "Closes",
|
||||||
Ref: "456",
|
Ref: "456",
|
||||||
Source: "username/repository",
|
Source: "username/repository",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Title: "BREAKING CHANGE",
|
Title: "BREAKING CHANGE",
|
||||||
Body: fmt.Sprintf(`This is multiline breaking change note.
|
Body: fmt.Sprintf(`This is multiline breaking change note.
|
||||||
It is treated as the body of the Note until a mention or reference appears.
|
It is treated as the body of the Note until a mention or reference appears.
|
||||||
|
|
@ -281,7 +281,7 @@ class MyController extends Controller {
|
||||||
Fixes #123
|
Fixes #123
|
||||||
Closes username/repository#456`, "```", "```"),
|
Closes username/repository#456`, "```", "```"),
|
||||||
},
|
},
|
||||||
&Commit{
|
{
|
||||||
Hash: &Hash{
|
Hash: &Hash{
|
||||||
Long: "123456789735dcc4810dda3312b0792236c97c4e",
|
Long: "123456789735dcc4810dda3312b0792236c97c4e",
|
||||||
Short: "12345678",
|
Short: "12345678",
|
||||||
|
|
@ -381,7 +381,7 @@ func TestCommitParserParseWithJira(t *testing.T) {
|
||||||
mock, mockJiraClient{}, &Config{
|
mock, mockJiraClient{}, &Config{
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
CommitFilters: map[string][]string{
|
CommitFilters: map[string][]string{
|
||||||
"Type": []string{
|
"Type": {
|
||||||
"feat",
|
"feat",
|
||||||
"fix",
|
"fix",
|
||||||
"perf",
|
"perf",
|
||||||
|
|
@ -391,7 +391,7 @@ func TestCommitParserParseWithJira(t *testing.T) {
|
||||||
HeaderPattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$",
|
HeaderPattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$",
|
||||||
HeaderPatternMaps: []string{
|
HeaderPatternMaps: []string{
|
||||||
"Type",
|
"Type",
|
||||||
"JiraIssueId",
|
"JiraIssueID",
|
||||||
"Subject",
|
"Subject",
|
||||||
},
|
},
|
||||||
JiraTypeMaps: map[string]string{
|
JiraTypeMaps: map[string]string{
|
||||||
|
|
@ -403,7 +403,7 @@ func TestCommitParserParseWithJira(t *testing.T) {
|
||||||
commits, err := parser.Parse("HEAD")
|
commits, err := parser.Parse("HEAD")
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
commit := commits[0]
|
commit := commits[0]
|
||||||
assert.Equal(commit.JiraIssueId, "JIRA-1111")
|
assert.Equal(commit.JiraIssueID, "JIRA-1111")
|
||||||
assert.Equal(commit.JiraIssue.Type, "Story")
|
assert.Equal(commit.JiraIssue.Type, "Story")
|
||||||
assert.Equal(commit.JiraIssue.Summary, "summary of JIRA-1111")
|
assert.Equal(commit.JiraIssue.Summary, "summary of JIRA-1111")
|
||||||
assert.Equal(commit.JiraIssue.Description, "description of JIRA-1111")
|
assert.Equal(commit.JiraIssue.Description, "description of JIRA-1111")
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ func Example() {
|
||||||
},
|
},
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
CommitFilters: map[string][]string{
|
CommitFilters: map[string][]string{
|
||||||
"Type": []string{
|
"Type": {
|
||||||
"feat",
|
"feat",
|
||||||
"fix",
|
"fix",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
14
fields.go
14
fields.go
|
|
@ -52,7 +52,7 @@ type NoteGroup struct {
|
||||||
Notes []*Note
|
Notes []*Note
|
||||||
}
|
}
|
||||||
|
|
||||||
// JiraIssue
|
// JiraIssue is information about a jira ticket (type, summary, description, and labels)
|
||||||
type JiraIssue struct {
|
type JiraIssue struct {
|
||||||
Type string
|
Type string
|
||||||
Summary string
|
Summary string
|
||||||
|
|
@ -69,13 +69,13 @@ type Commit struct {
|
||||||
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
|
||||||
JiraIssue *JiraIssue // If no issue id found in header, `nil` is assigned
|
JiraIssue *JiraIssue // If no issue id found in header, `nil` is assigned
|
||||||
Header string // (e.g. `feat(core)[RNWY-310]: Add new feature`)
|
Header string // (e.g. `feat(core)[RNWY-310]: Add new feature`)
|
||||||
Type string // (e.g. `feat`)
|
Type string // (e.g. `feat`)
|
||||||
Scope string // (e.g. `core`)
|
Scope string // (e.g. `core`)
|
||||||
Subject string // (e.g. `Add new feature`)
|
Subject string // (e.g. `Add new feature`)
|
||||||
JiraIssueId string // (e.g. `RNWY-310`)
|
JiraIssueID string // (e.g. `RNWY-310`)
|
||||||
Body string
|
Body string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
6
jira.go
6
jira.go
|
|
@ -4,6 +4,7 @@ import (
|
||||||
agjira "github.com/andygrunwald/go-jira"
|
agjira "github.com/andygrunwald/go-jira"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// JiraClient is an HTTP client for Jira
|
||||||
type JiraClient interface {
|
type JiraClient interface {
|
||||||
GetJiraIssue(id string) (*agjira.Issue, error)
|
GetJiraIssue(id string) (*agjira.Issue, error)
|
||||||
}
|
}
|
||||||
|
|
@ -14,11 +15,12 @@ type jiraClient struct {
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewJiraClient returns an instance of JiraClient
|
||||||
func NewJiraClient(config *Config) JiraClient {
|
func NewJiraClient(config *Config) JiraClient {
|
||||||
return jiraClient{
|
return jiraClient{
|
||||||
username: config.Options.JiraUsername,
|
username: config.Options.JiraUsername,
|
||||||
token: config.Options.JiraToken,
|
token: config.Options.JiraToken,
|
||||||
url: config.Options.JiraUrl,
|
url: config.Options.JiraURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
package chglog
|
package chglog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestJira(t *testing.T) {
|
func TestJira(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
config := &Config {
|
config := &Config{
|
||||||
Options: &Options{
|
Options: &Options{
|
||||||
Processor: nil,
|
Processor: nil,
|
||||||
NextTag: "",
|
NextTag: "",
|
||||||
|
|
@ -29,7 +30,7 @@ func TestJira(t *testing.T) {
|
||||||
NoteKeywords: nil,
|
NoteKeywords: nil,
|
||||||
JiraUsername: "uuu",
|
JiraUsername: "uuu",
|
||||||
JiraToken: "ppp",
|
JiraToken: "ppp",
|
||||||
JiraUrl: "http://jira.com",
|
JiraURL: "http://jira.com",
|
||||||
JiraTypeMaps: nil,
|
JiraTypeMaps: nil,
|
||||||
JiraIssueDescriptionPattern: "",
|
JiraIssueDescriptionPattern: "",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
emoji "github.com/kyokomi/emoji/v2"
|
"github.com/kyokomi/emoji/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger ...
|
// Logger ...
|
||||||
|
|
@ -26,7 +26,7 @@ func NewLogger(stdout, stderr io.Writer, silent, noEmoji bool) *Logger {
|
||||||
stderr: stderr,
|
stderr: stderr,
|
||||||
silent: silent,
|
silent: silent,
|
||||||
noEmoji: noEmoji,
|
noEmoji: noEmoji,
|
||||||
reEmoji: regexp.MustCompile(":[\\w\\+_\\-]+:\\s?"),
|
reEmoji: regexp.MustCompile(`:[\w\+_\-]+:\s?`),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
emoji "github.com/kyokomi/emoji/v2"
|
emoji "github.com/kyokomi/emoji/v2"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoggerLogSilent(t *testing.T) {
|
func TestLoggerLogSilent(t *testing.T) {
|
||||||
|
|
@ -40,7 +40,7 @@ func TestLoggerLogNoEmoji(t *testing.T) {
|
||||||
stderr := &bytes.Buffer{}
|
stderr := &bytes.Buffer{}
|
||||||
logger := NewLogger(stdout, stderr, false, true)
|
logger := NewLogger(stdout, stderr, false, true)
|
||||||
logger.Log(":+1:Hello, World! :)")
|
logger.Log(":+1:Hello, World! :)")
|
||||||
assert.Equal(fmt.Sprint("Hello, World! :)\n"), stdout.String())
|
assert.Equal(fmt.Sprint("Hello, World! :)\n"), stdout.String()) //nolint:gosimple
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoggerError(t *testing.T) {
|
func TestLoggerError(t *testing.T) {
|
||||||
|
|
|
||||||
12
processor.go
12
processor.go
|
|
@ -33,8 +33,8 @@ func (p *GitHubProcessor) Bootstrap(config *Config) {
|
||||||
p.Host = strings.TrimRight(p.Host, "/")
|
p.Host = strings.TrimRight(p.Host, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.reMention = regexp.MustCompile("@(\\w+)")
|
p.reMention = regexp.MustCompile(`@(\w+)`)
|
||||||
p.reIssue = regexp.MustCompile("(?i)(#|gh-)(\\d+)")
|
p.reIssue = regexp.MustCompile(`(?i)(#|gh-)(\d+)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessCommit ...
|
// ProcessCommit ...
|
||||||
|
|
@ -88,8 +88,8 @@ func (p *GitLabProcessor) Bootstrap(config *Config) {
|
||||||
p.Host = strings.TrimRight(p.Host, "/")
|
p.Host = strings.TrimRight(p.Host, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.reMention = regexp.MustCompile("@(\\w+)")
|
p.reMention = regexp.MustCompile(`@(\w+)`)
|
||||||
p.reIssue = regexp.MustCompile("(?i)#(\\d+)")
|
p.reIssue = regexp.MustCompile(`(?i)#(\d+)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessCommit ...
|
// ProcessCommit ...
|
||||||
|
|
@ -143,8 +143,8 @@ func (p *BitbucketProcessor) Bootstrap(config *Config) {
|
||||||
p.Host = strings.TrimRight(p.Host, "/")
|
p.Host = strings.TrimRight(p.Host, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.reMention = regexp.MustCompile("@(\\w+)")
|
p.reMention = regexp.MustCompile(`@(\w+)`)
|
||||||
p.reIssue = regexp.MustCompile("(?i)#(\\d+)")
|
p.reIssue = regexp.MustCompile(`(?i)#(\d+)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessCommit ...
|
// ProcessCommit ...
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestGitHubProcessor(t *testing.T) {
|
||||||
multiline [#789](https://example.com/issues/789)
|
multiline [#789](https://example.com/issues/789)
|
||||||
[@foo](https://github.com/foo), [@bar](https://github.com/bar)`,
|
[@foo](https://github.com/foo), [@bar](https://github.com/bar)`,
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Body: `issue1 [#11](https://example.com/issues/11)
|
Body: `issue1 [#11](https://example.com/issues/11)
|
||||||
issue2 [#22](https://example.com/issues/22)
|
issue2 [#22](https://example.com/issues/22)
|
||||||
[gh-56](https://example.com/issues/56) hoge fuga`,
|
[gh-56](https://example.com/issues/56) hoge fuga`,
|
||||||
|
|
@ -42,7 +42,7 @@ issue2 [#22](https://example.com/issues/22)
|
||||||
multiline #789
|
multiline #789
|
||||||
@foo, @bar`,
|
@foo, @bar`,
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Body: `issue1 #11
|
Body: `issue1 #11
|
||||||
issue2 #22
|
issue2 #22
|
||||||
gh-56 hoge fuga`,
|
gh-56 hoge fuga`,
|
||||||
|
|
@ -89,7 +89,7 @@ func TestGitLabProcessor(t *testing.T) {
|
||||||
multiline [#789](https://example.com/issues/789)
|
multiline [#789](https://example.com/issues/789)
|
||||||
[@foo](https://gitlab.com/foo), [@bar](https://gitlab.com/bar)`,
|
[@foo](https://gitlab.com/foo), [@bar](https://gitlab.com/bar)`,
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Body: `issue1 [#11](https://example.com/issues/11)
|
Body: `issue1 [#11](https://example.com/issues/11)
|
||||||
issue2 [#22](https://example.com/issues/22)
|
issue2 [#22](https://example.com/issues/22)
|
||||||
gh-56 hoge fuga`,
|
gh-56 hoge fuga`,
|
||||||
|
|
@ -104,7 +104,7 @@ gh-56 hoge fuga`,
|
||||||
multiline #789
|
multiline #789
|
||||||
@foo, @bar`,
|
@foo, @bar`,
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Body: `issue1 #11
|
Body: `issue1 #11
|
||||||
issue2 #22
|
issue2 #22
|
||||||
gh-56 hoge fuga`,
|
gh-56 hoge fuga`,
|
||||||
|
|
@ -151,7 +151,7 @@ func TestBitbucketProcessor(t *testing.T) {
|
||||||
multiline [#789](https://example.com/issues/789/)
|
multiline [#789](https://example.com/issues/789/)
|
||||||
[@foo](https://bitbucket.org/foo/), [@bar](https://bitbucket.org/bar/)`,
|
[@foo](https://bitbucket.org/foo/), [@bar](https://bitbucket.org/bar/)`,
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Body: `issue1 [#11](https://example.com/issues/11/)
|
Body: `issue1 [#11](https://example.com/issues/11/)
|
||||||
issue2 [#22](https://example.com/issues/22/)
|
issue2 [#22](https://example.com/issues/22/)
|
||||||
gh-56 hoge fuga`,
|
gh-56 hoge fuga`,
|
||||||
|
|
@ -166,7 +166,7 @@ gh-56 hoge fuga`,
|
||||||
multiline #789
|
multiline #789
|
||||||
@foo, @bar`,
|
@foo, @bar`,
|
||||||
Notes: []*Note{
|
Notes: []*Note{
|
||||||
&Note{
|
{
|
||||||
Body: `issue1 #11
|
Body: `issue1 #11
|
||||||
issue2 #22
|
issue2 #22
|
||||||
gh-56 hoge fuga`,
|
gh-56 hoge fuga`,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
type tagReader struct {
|
type tagReader struct {
|
||||||
client gitcmd.Client
|
client gitcmd.Client
|
||||||
format string
|
|
||||||
separator string
|
separator string
|
||||||
reFilter *regexp.Regexp
|
reFilter *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +35,7 @@ func (r *tagReader) ReadAll() ([]*Tag, error) {
|
||||||
tags := []*Tag{}
|
tags := []*Tag{}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tags, fmt.Errorf("failed to get git-tag: %s", err.Error())
|
return tags, fmt.Errorf("failed to get git-tag: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(out, "\n")
|
lines := strings.Split(out, "\n")
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func TestTagReader(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
[]*Tag{
|
[]*Tag{
|
||||||
&Tag{
|
{
|
||||||
Name: "hoge_fuga",
|
Name: "hoge_fuga",
|
||||||
Subject: "Invalid semver tag name",
|
Subject: "Invalid semver tag name",
|
||||||
Date: time.Date(2018, 3, 12, 12, 30, 10, 0, time.UTC),
|
Date: time.Date(2018, 3, 12, 12, 30, 10, 0, time.UTC),
|
||||||
|
|
@ -44,7 +44,7 @@ func TestTagReader(t *testing.T) {
|
||||||
Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC),
|
Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&Tag{
|
{
|
||||||
Name: "5.0.0-rc.0",
|
Name: "5.0.0-rc.0",
|
||||||
Subject: "Release 5.0.0-rc.0",
|
Subject: "Release 5.0.0-rc.0",
|
||||||
Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC),
|
Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC),
|
||||||
|
|
@ -59,7 +59,7 @@ func TestTagReader(t *testing.T) {
|
||||||
Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC),
|
Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&Tag{
|
{
|
||||||
Name: "4.4.4",
|
Name: "4.4.4",
|
||||||
Subject: "Release 4.4.4",
|
Subject: "Release 4.4.4",
|
||||||
Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC),
|
Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC),
|
||||||
|
|
@ -74,7 +74,7 @@ func TestTagReader(t *testing.T) {
|
||||||
Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC),
|
Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&Tag{
|
{
|
||||||
Name: "4.4.3",
|
Name: "4.4.3",
|
||||||
Subject: "This is tag subject",
|
Subject: "This is tag subject",
|
||||||
Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC),
|
Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC),
|
||||||
|
|
@ -89,7 +89,7 @@ func TestTagReader(t *testing.T) {
|
||||||
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&Tag{
|
{
|
||||||
Name: "v2.0.4-beta.1",
|
Name: "v2.0.4-beta.1",
|
||||||
Subject: "Release v2.0.4-beta.1",
|
Subject: "Release v2.0.4-beta.1",
|
||||||
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||||
|
|
@ -104,11 +104,11 @@ func TestTagReader(t *testing.T) {
|
||||||
actual,
|
actual,
|
||||||
)
|
)
|
||||||
|
|
||||||
actual_filtered, err_filtered := newTagReader(client, "^v").ReadAll()
|
actualFiltered, errFiltered := newTagReader(client, "^v").ReadAll()
|
||||||
assert.Nil(err_filtered)
|
assert.Nil(errFiltered)
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
[]*Tag{
|
[]*Tag{
|
||||||
&Tag{
|
{
|
||||||
Name: "v2.0.4-beta.1",
|
Name: "v2.0.4-beta.1",
|
||||||
Subject: "Release v2.0.4-beta.1",
|
Subject: "Release v2.0.4-beta.1",
|
||||||
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||||
|
|
@ -116,6 +116,6 @@ func TestTagReader(t *testing.T) {
|
||||||
Previous: nil,
|
Previous: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actual_filtered,
|
actualFiltered,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,16 @@ func (s *tagSelector) Select(tags []*Tag, query string) ([]*Tag, string, error)
|
||||||
case 2:
|
case 2:
|
||||||
old := tokens[0]
|
old := tokens[0]
|
||||||
new := tokens[1]
|
new := tokens[1]
|
||||||
if old == "" && new == "" {
|
switch {
|
||||||
|
case old == "" && new == "":
|
||||||
return nil, "", nil
|
return nil, "", nil
|
||||||
} else if old == "" {
|
case old == "":
|
||||||
return s.selectBeforeTags(tags, new)
|
return s.selectBeforeTags(tags, new)
|
||||||
} else if new == "" {
|
case new == "":
|
||||||
return s.selectAfterTags(tags, old)
|
return s.selectAfterTags(tags, old)
|
||||||
|
default:
|
||||||
|
return s.selectRangeTags(tags, tokens[0], tokens[1])
|
||||||
}
|
}
|
||||||
return s.selectRangeTags(tags, tokens[0], tokens[1])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, "", errFailedQueryParse
|
return nil, "", errFailedQueryParse
|
||||||
|
|
@ -76,7 +78,8 @@ func (*tagSelector) selectBeforeTags(tags []*Tag, token string) ([]*Tag, string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*tagSelector) selectAfterTags(tags []*Tag, token string) ([]*Tag, string, error) {
|
func (*tagSelector) selectAfterTags(tags []*Tag, token string) ([]*Tag, string, error) {
|
||||||
var (
|
// NOTE(clok): the res slice can range in size based on the token passed in.
|
||||||
|
var ( //nolint:prealloc
|
||||||
res []*Tag
|
res []*Tag
|
||||||
from string
|
from string
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,51 +12,51 @@ func TestTagSelector(t *testing.T) {
|
||||||
selector := newTagSelector()
|
selector := newTagSelector()
|
||||||
|
|
||||||
fixtures := []*Tag{
|
fixtures := []*Tag{
|
||||||
&Tag{Name: "2.2.12-rc.12"},
|
{Name: "2.2.12-rc.12"},
|
||||||
&Tag{Name: "2.1.0"},
|
{Name: "2.1.0"},
|
||||||
&Tag{Name: "v2.0.0-beta.1"},
|
{Name: "v2.0.0-beta.1"},
|
||||||
&Tag{Name: "v1.2.9"},
|
{Name: "v1.2.9"},
|
||||||
&Tag{Name: "v1.0.0"},
|
{Name: "v1.0.0"},
|
||||||
}
|
}
|
||||||
|
|
||||||
table := map[string][]string{
|
table := map[string][]string{
|
||||||
// Single
|
// Single
|
||||||
"2.2.12-rc.12": []string{
|
"2.2.12-rc.12": {
|
||||||
"2.2.12-rc.12",
|
"2.2.12-rc.12",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
},
|
},
|
||||||
"v2.0.0-beta.1": []string{
|
"v2.0.0-beta.1": {
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
"v1.2.9",
|
"v1.2.9",
|
||||||
},
|
},
|
||||||
"v1.0.0": []string{
|
"v1.0.0": {
|
||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
// ~ <tag>
|
// ~ <tag>
|
||||||
"..2.1.0": []string{
|
"..2.1.0": {
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
"v1.2.9",
|
"v1.2.9",
|
||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
"..v1.0.0": []string{
|
"..v1.0.0": {
|
||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
// <tag> ~
|
// <tag> ~
|
||||||
"v2.0.0-beta.1..": []string{
|
"v2.0.0-beta.1..": {
|
||||||
"2.2.12-rc.12",
|
"2.2.12-rc.12",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
"v1.2.9",
|
"v1.2.9",
|
||||||
},
|
},
|
||||||
"2.2.12-rc.12..": []string{
|
"2.2.12-rc.12..": {
|
||||||
"2.2.12-rc.12",
|
"2.2.12-rc.12",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
},
|
},
|
||||||
"v1.0.0..": []string{
|
"v1.0.0..": {
|
||||||
"2.2.12-rc.12",
|
"2.2.12-rc.12",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
|
|
@ -65,7 +65,7 @@ func TestTagSelector(t *testing.T) {
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
// <tag> ~ <tag>
|
// <tag> ~ <tag>
|
||||||
"v1.0.0..2.2.12-rc.12": []string{
|
"v1.0.0..2.2.12-rc.12": {
|
||||||
"2.2.12-rc.12",
|
"2.2.12-rc.12",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
|
|
@ -73,13 +73,13 @@ func TestTagSelector(t *testing.T) {
|
||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
"v1.0.0..v2.0.0-beta.1": []string{
|
"v1.0.0..v2.0.0-beta.1": {
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
"v1.2.9",
|
"v1.2.9",
|
||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
"v1.2.9..2.1.0": []string{
|
"v1.2.9..2.1.0": {
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
"v2.0.0-beta.1",
|
"v2.0.0-beta.1",
|
||||||
"v1.2.9",
|
"v1.2.9",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue