mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-22 18:06:11 +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
|
||||
changelog:
|
||||
@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_maps:
|
||||
- Type
|
||||
- JiraIssueId
|
||||
- JiraIssueID
|
||||
- Subject
|
||||
```
|
||||
|
||||
|
|
@ -646,6 +646,8 @@ We alway welcome your contributions :clap:
|
|||
1. Fork (https://github.com/git-chglog/git-chglog) :tada:
|
||||
1. Create a feature branch :coffee:
|
||||
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. Rebase your local changes against the `master` branch :bulb:
|
||||
1. Create new Pull Request :love_letter:
|
||||
|
|
|
|||
39
chglog.go
39
chglog.go
|
|
@ -5,13 +5,14 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
||||
"github.com/tsuyoshiwada/go-gitcmd"
|
||||
)
|
||||
|
||||
// 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`)
|
||||
JiraUsername string
|
||||
JiraToken string
|
||||
JiraUrl string
|
||||
JiraURL string
|
||||
JiraTypeMaps map[string]string
|
||||
JiraIssueDescriptionPattern string
|
||||
Paths []string // Path filter
|
||||
|
|
@ -138,7 +139,11 @@ func (gen *Generator) Generate(w io.Writer, query string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer back()
|
||||
defer func() {
|
||||
if err = back(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
tags, first, err := gen.getTags(query)
|
||||
if err != nil {
|
||||
|
|
@ -269,7 +274,7 @@ func (gen *Generator) getTags(query string) ([]*Tag, string, error) {
|
|||
|
||||
// Assign the date with `readVersions()`
|
||||
tags = append([]*Tag{
|
||||
&Tag{
|
||||
{
|
||||
Name: next,
|
||||
Subject: next,
|
||||
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 {
|
||||
return input.Format(layout)
|
||||
},
|
||||
// check whether substs is withing s
|
||||
"contains": func(s, substr string) bool {
|
||||
return strings.Contains(s, substr)
|
||||
},
|
||||
// check whether substr is within s
|
||||
"contains": strings.Contains,
|
||||
// check whether s begins with prefix
|
||||
"hasPrefix": func(s, prefix string) bool {
|
||||
return strings.HasPrefix(s, prefix)
|
||||
},
|
||||
"hasPrefix": strings.HasPrefix,
|
||||
// check whether s ends with suffix
|
||||
"hasSuffix": func(s, suffix string) bool {
|
||||
return strings.HasSuffix(s, suffix)
|
||||
},
|
||||
"hasSuffix": strings.HasSuffix,
|
||||
// replace the first n instances of old with new
|
||||
"replace": func(s, old, new string, n int) string {
|
||||
return strings.Replace(s, old, new, n)
|
||||
},
|
||||
"replace": strings.Replace,
|
||||
// lower case a string
|
||||
"lower": func(s string) string {
|
||||
return strings.ToLower(s)
|
||||
},
|
||||
"lower": strings.ToLower,
|
||||
// upper case a string
|
||||
"upper": func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
},
|
||||
"upper": strings.ToUpper,
|
||||
// upper case the first character of a string
|
||||
"upperFirst": func(s string) string {
|
||||
if len(s) > 0 {
|
||||
|
|
|
|||
|
|
@ -32,17 +32,17 @@ func TestMain(m *testing.M) {
|
|||
func setup(dir string, setupRepo func(commitFunc, tagFunc, gitcmd.Client)) {
|
||||
testDir := filepath.Join(cwd, testRepoRoot, dir)
|
||||
|
||||
os.RemoveAll(testDir)
|
||||
os.MkdirAll(testDir, os.ModePerm)
|
||||
os.Chdir(testDir)
|
||||
_ = os.RemoveAll(testDir)
|
||||
_ = os.MkdirAll(testDir, os.ModePerm)
|
||||
_ = os.Chdir(testDir)
|
||||
|
||||
loc, _ := time.LoadLocation("UTC")
|
||||
time.Local = loc
|
||||
|
||||
git := gitcmd.New(nil)
|
||||
git.Exec("init")
|
||||
git.Exec("config", "user.name", "test_user")
|
||||
git.Exec("config", "user.email", "test@example.com")
|
||||
_, _ = git.Exec("init")
|
||||
_, _ = git.Exec("config", "user.name", "test_user")
|
||||
_, _ = git.Exec("config", "user.email", "test@example.com")
|
||||
|
||||
var commit = func(date, subject, body string) {
|
||||
msg := subject
|
||||
|
|
@ -51,21 +51,21 @@ func setup(dir string, setupRepo func(commitFunc, tagFunc, gitcmd.Client)) {
|
|||
}
|
||||
t, _ := time.Parse(internalTimeFormat, date)
|
||||
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) {
|
||||
git.Exec("tag", name)
|
||||
_, _ = git.Exec("tag", name)
|
||||
}
|
||||
|
||||
setupRepo(commit, tag, git)
|
||||
|
||||
os.Chdir(cwd)
|
||||
_ = os.Chdir(cwd)
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
os.Chdir(cwd)
|
||||
os.RemoveAll(filepath.Join(cwd, testRepoRoot))
|
||||
_ = os.Chdir(cwd)
|
||||
_ = os.RemoveAll(filepath.Join(cwd, testRepoRoot))
|
||||
}
|
||||
|
||||
func TestGeneratorNotFoundTags(t *testing.T) {
|
||||
|
|
@ -193,7 +193,7 @@ func TestGeneratorWithTypeScopeSubject(t *testing.T) {
|
|||
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: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:
|
||||
Multiple
|
||||
|
|
@ -216,7 +216,7 @@ change message.`)
|
|||
},
|
||||
Options: &Options{
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"Type": {
|
||||
"feat",
|
||||
"fix",
|
||||
},
|
||||
|
|
@ -256,7 +256,7 @@ change message.`)
|
|||
|
||||
buf := &bytes.Buffer{}
|
||||
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.Equal(`<a name="unreleased"></a>
|
||||
|
|
@ -270,7 +270,7 @@ change message.`)
|
|||
## [2.0.0-beta.0] - 2018-01-03
|
||||
### Features
|
||||
- **context:** Online breaking change
|
||||
- **router:** Muliple breaking change
|
||||
- **router:** Multiple breaking change
|
||||
|
||||
### BREAKING CHANGE
|
||||
|
||||
|
|
@ -331,7 +331,7 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
|||
Options: &Options{
|
||||
NextTag: "3.0.0",
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"Type": {
|
||||
"feat",
|
||||
},
|
||||
},
|
||||
|
|
@ -352,7 +352,7 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
|||
|
||||
buf := &bytes.Buffer{}
|
||||
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.Equal(`<a name="unreleased"></a>
|
||||
|
|
@ -383,7 +383,7 @@ func TestGeneratorWithNextTag(t *testing.T) {
|
|||
|
||||
buf = &bytes.Buffer{}
|
||||
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.Equal(`<a name="unreleased"></a>
|
||||
|
|
@ -424,7 +424,7 @@ func TestGeneratorWithTagFiler(t *testing.T) {
|
|||
Options: &Options{
|
||||
TagFilterPattern: "^v",
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"Type": {
|
||||
"feat",
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ import (
|
|||
"regexp"
|
||||
"testing"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
func TestCLIForStdout(t *testing.T) {
|
||||
|
|
@ -36,7 +37,7 @@ func TestCLIForStdout(t *testing.T) {
|
|||
if config.Bin != "/custom/bin/git" {
|
||||
return errors.New("")
|
||||
}
|
||||
w.Write([]byte("success!!"))
|
||||
_, _ = w.Write([]byte("success!!"))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -104,7 +105,7 @@ func TestCLIForFile(t *testing.T) {
|
|||
if filepath.ToSlash(config.Bin) != "/custom/bin/git" {
|
||||
return errors.New("")
|
||||
}
|
||||
w.Write([]byte("success!!"))
|
||||
_, _ = w.Write([]byte("success!!"))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
// Info ...
|
||||
|
|
@ -49,6 +50,7 @@ type NoteOptions struct {
|
|||
Keywords []string `yaml:"keywords"`
|
||||
}
|
||||
|
||||
// JiraClientInfoOptions ...
|
||||
type JiraClientInfoOptions struct {
|
||||
Username string `yaml:"username"`
|
||||
Token string `yaml:"token"`
|
||||
|
|
@ -286,7 +288,7 @@ func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
|||
Template: orValue(ctx.Template, config.Template),
|
||||
Info: &chglog.Info{
|
||||
Title: info.Title,
|
||||
RepositoryURL: orValue(ctx.RepositoryUrl, info.RepositoryURL),
|
||||
RepositoryURL: orValue(ctx.RepositoryURL, info.RepositoryURL),
|
||||
},
|
||||
Options: &chglog.Options{
|
||||
NextTag: ctx.NextTag,
|
||||
|
|
@ -309,7 +311,7 @@ func (config *Config) Convert(ctx *CLIContext) *chglog.Config {
|
|||
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),
|
||||
JiraURL: orValue(ctx.JiraURL, opts.Jira.ClintInfo.URL),
|
||||
JiraTypeMaps: opts.Jira.Issue.TypeMaps,
|
||||
JiraIssueDescriptionPattern: opts.Jira.Issue.DescriptionPattern,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package main
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// ConfigLoader ...
|
||||
|
|
@ -20,7 +21,8 @@ func NewConfigLoader() ConfigLoader {
|
|||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type CLIContext struct {
|
|||
Stderr io.Writer
|
||||
ConfigPath string
|
||||
Template string
|
||||
RepositoryUrl string
|
||||
RepositoryURL string
|
||||
OutputPath string
|
||||
Silent bool
|
||||
NoColor bool
|
||||
|
|
@ -22,7 +22,7 @@ type CLIContext struct {
|
|||
TagFilterPattern string
|
||||
JiraUsername string
|
||||
JiraToken string
|
||||
JiraUrl string
|
||||
JiraURL string
|
||||
Paths []string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func (t *customTemplateBuilderImpl) Build(ans *Answer) (string, error) {
|
|||
tpl += t.versionHeader(ans.Style, ans.Template)
|
||||
|
||||
// commits
|
||||
tpl += t.commits(ans.Template, ans.CommitMessageFormat)
|
||||
tpl += t.commits(ans.CommitMessageFormat)
|
||||
|
||||
// revert
|
||||
if ans.IncludeReverts {
|
||||
|
|
@ -75,7 +75,7 @@ func (*customTemplateBuilderImpl) versionHeader(style, template string) string {
|
|||
return tpl
|
||||
}
|
||||
|
||||
func (*customTemplateBuilderImpl) commits(template, format string) string {
|
||||
func (*customTemplateBuilderImpl) commits(format string) string {
|
||||
var (
|
||||
header string
|
||||
body string
|
||||
|
|
|
|||
|
|
@ -2,17 +2,16 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/git-chglog/git-chglog"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fatih/color"
|
||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
// Initializer ...
|
||||
type Initializer struct {
|
||||
ctx *InitContext
|
||||
client gitcmd.Client
|
||||
fs FileSystem
|
||||
logger *chglog.Logger
|
||||
questioner Questioner
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/mattn/go-colorable"
|
||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
||||
"github.com/tsuyoshiwada/go-gitcmd"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// CreateApp creates and initializes CLI application
|
||||
// with description, flags, version, etc.
|
||||
func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
||||
ttl := color.New(color.FgYellow).SprintFunc()
|
||||
|
||||
|
|
@ -182,6 +185,8 @@ func CreateApp(actionFunc cli.ActionFunc) *cli.App {
|
|||
return app
|
||||
}
|
||||
|
||||
// AppAction is a callback function to create initializer
|
||||
// and CLIContext and ultimately run the application.
|
||||
func AppAction(c *cli.Context) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
|
@ -219,7 +224,7 @@ func AppAction(c *cli.Context) error {
|
|||
Stderr: colorable.NewColorableStderr(),
|
||||
ConfigPath: c.String("config"),
|
||||
Template: c.String("template"),
|
||||
RepositoryUrl: c.String("repository-url"),
|
||||
RepositoryURL: c.String("repository-url"),
|
||||
OutputPath: c.String("output"),
|
||||
Silent: c.Bool("silent"),
|
||||
NoColor: c.Bool("no-color"),
|
||||
|
|
@ -230,7 +235,7 @@ func AppAction(c *cli.Context) error {
|
|||
TagFilterPattern: c.String("tag-filter-pattern"),
|
||||
JiraUsername: c.String("jira-username"),
|
||||
JiraToken: c.String("jira-token"),
|
||||
JiraUrl: c.String("jira-url"),
|
||||
JiraURL: c.String("jira-url"),
|
||||
Paths: c.StringSlice("path"),
|
||||
},
|
||||
fs,
|
||||
|
|
@ -245,5 +250,8 @@ func AppAction(c *cli.Context) error {
|
|||
|
||||
func main() {
|
||||
app := CreateApp(AppAction)
|
||||
app.Run(os.Args)
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli/v2"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var gAssert *assert.Assertions
|
||||
|
||||
func mock_app_action(c *cli.Context) error {
|
||||
func mockAppAction(c *cli.Context) error {
|
||||
assert := gAssert
|
||||
assert.Equal("c.yml", c.String("config"))
|
||||
assert.Equal("^v", c.String("tag-filter-pattern"))
|
||||
|
|
@ -25,7 +27,7 @@ func TestCreateApp(t *testing.T) {
|
|||
assert.True(true)
|
||||
gAssert = assert
|
||||
|
||||
app := CreateApp(mock_app_action)
|
||||
app := CreateApp(mockAppAction)
|
||||
args := []string{
|
||||
"git-chglog",
|
||||
"--silent",
|
||||
|
|
@ -36,5 +38,8 @@ func TestCreateApp(t *testing.T) {
|
|||
"--next-tag", "v5",
|
||||
"--tag-filter-pattern", "^v",
|
||||
}
|
||||
app.Run(args)
|
||||
err := app.Run(args)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ package main
|
|||
import (
|
||||
"testing"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
func TestProcessorFactory(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
||||
survey "github.com/AlecAivazis/survey/v2"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/tsuyoshiwada/go-gitcmd"
|
||||
)
|
||||
|
||||
// Answer ...
|
||||
|
|
@ -52,11 +52,12 @@ func (q *questionerImpl) Ask() (*Answer, error) {
|
|||
t := q.fs.Exists(tpl)
|
||||
msg := ""
|
||||
|
||||
if c && t {
|
||||
switch {
|
||||
case c && t:
|
||||
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)
|
||||
} else if t {
|
||||
case t:
|
||||
msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", tpl)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
var reSSH = regexp.MustCompile("^\\w+@([\\w\\.\\-]+):([\\w\\.\\-]+)\\/([\\w\\.\\-]+)$")
|
||||
var reSSH = regexp.MustCompile(`^\w+@([\w\.\-]+):([\w\.\-]+)\/([\w\.\-]+)$`)
|
||||
|
||||
func remoteOriginURLToHTTP(rawurl string) string {
|
||||
if rawurl == "" {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func (f *CommitMessageFormat) PatternMapString() string {
|
|||
return fmt.Sprintf("\n%s", strings.Join(arr, "\n"))
|
||||
}
|
||||
|
||||
// FilterTypeString ...
|
||||
// FilterTypesString ...
|
||||
func (f *CommitMessageFormat) FilterTypesString() string {
|
||||
if len(f.typeSamples) == 0 {
|
||||
return " []"
|
||||
|
|
|
|||
|
|
@ -127,7 +127,11 @@ func (e *commitExtractor) commitGroupTitle(commit *Commit) (string, string) {
|
|||
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)
|
||||
if e.opts.CommitGroupSortBy == "Custom" {
|
||||
for i, t := range e.opts.CommitGroupTitleOrder {
|
||||
|
|
@ -136,6 +140,9 @@ func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
if e.opts.CommitGroupSortBy == "Custom" {
|
||||
return order[groups[i].RawTitle] < order[groups[j].RawTitle]
|
||||
|
|
@ -165,6 +172,11 @@ func (e *commitExtractor) sortCommitGroups(groups []*CommitGroup) {
|
|||
|
||||
// commits
|
||||
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 {
|
||||
var (
|
||||
a, b interface{}
|
||||
|
|
@ -198,6 +210,7 @@ func (e *commitExtractor) sortNoteGroups(groups []*NoteGroup) {
|
|||
|
||||
// notes
|
||||
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 {
|
||||
return strings.ToLower(group.Notes[i].Title) < strings.ToLower(group.Notes[j].Title)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ func TestCommitExtractor(t *testing.T) {
|
|||
|
||||
fixtures := []*Commit{
|
||||
// [0]
|
||||
&Commit{
|
||||
{
|
||||
Type: "foo",
|
||||
Scope: "c",
|
||||
Header: "1",
|
||||
Notes: []*Note{},
|
||||
},
|
||||
// [1]
|
||||
&Commit{
|
||||
{
|
||||
Type: "foo",
|
||||
Scope: "b",
|
||||
Header: "2",
|
||||
|
|
@ -37,7 +37,7 @@ func TestCommitExtractor(t *testing.T) {
|
|||
},
|
||||
},
|
||||
// [2]
|
||||
&Commit{
|
||||
{
|
||||
Type: "bar",
|
||||
Scope: "d",
|
||||
Header: "3",
|
||||
|
|
@ -47,7 +47,7 @@ func TestCommitExtractor(t *testing.T) {
|
|||
},
|
||||
},
|
||||
// [3]
|
||||
&Commit{
|
||||
{
|
||||
Type: "foo",
|
||||
Scope: "a",
|
||||
Header: "4",
|
||||
|
|
@ -56,7 +56,7 @@ func TestCommitExtractor(t *testing.T) {
|
|||
},
|
||||
},
|
||||
// [4]
|
||||
&Commit{
|
||||
{
|
||||
Type: "",
|
||||
Scope: "",
|
||||
Header: "Merge1",
|
||||
|
|
@ -67,7 +67,7 @@ func TestCommitExtractor(t *testing.T) {
|
|||
},
|
||||
},
|
||||
// [5]
|
||||
&Commit{
|
||||
{
|
||||
Type: "",
|
||||
Scope: "",
|
||||
Header: "Revert1",
|
||||
|
|
@ -81,14 +81,14 @@ func TestCommitExtractor(t *testing.T) {
|
|||
commitGroups, mergeCommits, revertCommits, noteGroups := extractor.Extract(fixtures)
|
||||
|
||||
assert.Equal([]*CommitGroup{
|
||||
&CommitGroup{
|
||||
{
|
||||
RawTitle: "bar",
|
||||
Title: "BAR",
|
||||
Commits: []*Commit{
|
||||
fixtures[2],
|
||||
},
|
||||
},
|
||||
&CommitGroup{
|
||||
{
|
||||
RawTitle: "foo",
|
||||
Title: "Foo",
|
||||
Commits: []*Commit{
|
||||
|
|
@ -108,26 +108,26 @@ func TestCommitExtractor(t *testing.T) {
|
|||
}, revertCommits)
|
||||
|
||||
assert.Equal([]*NoteGroup{
|
||||
&NoteGroup{
|
||||
{
|
||||
Title: "note1-title",
|
||||
Notes: []*Note{
|
||||
fixtures[1].Notes[0],
|
||||
fixtures[2].Notes[0],
|
||||
},
|
||||
},
|
||||
&NoteGroup{
|
||||
{
|
||||
Title: "note2-title",
|
||||
Notes: []*Note{
|
||||
fixtures[1].Notes[1],
|
||||
},
|
||||
},
|
||||
&NoteGroup{
|
||||
{
|
||||
Title: "note3-title",
|
||||
Notes: []*Note{
|
||||
fixtures[2].Notes[1],
|
||||
},
|
||||
},
|
||||
&NoteGroup{
|
||||
{
|
||||
Title: "note4-title",
|
||||
Notes: []*Note{
|
||||
fixtures[3].Notes[0],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ import (
|
|||
"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{}
|
||||
|
||||
for _, commit := range commits {
|
||||
|
|
|
|||
|
|
@ -18,27 +18,27 @@ func TestCommitFilter(t *testing.T) {
|
|||
}
|
||||
|
||||
fixtures := []*Commit{
|
||||
&Commit{
|
||||
{
|
||||
Type: "foo",
|
||||
Scope: "hoge",
|
||||
Subject: "1",
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Type: "foo",
|
||||
Scope: "fuga",
|
||||
Subject: "2",
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Type: "bar",
|
||||
Scope: "hoge",
|
||||
Subject: "3",
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Type: "bar",
|
||||
Scope: "fuga",
|
||||
Subject: "4",
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Type: "Bar",
|
||||
Scope: "hogera",
|
||||
Subject: "5",
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func newCommitParser(logger *Logger, client gitcmd.Client, jiraClient JiraClient
|
|||
reRef: regexp.MustCompile("(?i)(" + joinedRefActions + ")\\s?([\\w/\\.\\-]+)?(?:" + joinedIssuePrefix + ")(\\d+)"),
|
||||
reIssue: regexp.MustCompile("(?:" + joinedIssuePrefix + ")(\\d+)"),
|
||||
reNotes: regexp.MustCompile("^(?i)\\s*(" + joinedNoteKeywords + ")[:\\s]+(.*)"),
|
||||
reMention: regexp.MustCompile("@([\\w-]+)"),
|
||||
reMention: regexp.MustCompile(`@([\w-]+)`),
|
||||
reJiraIssueDescription: regexp.MustCompile(opts.JiraIssueDescriptionPattern),
|
||||
}
|
||||
}
|
||||
|
|
@ -223,8 +223,8 @@ func (p *commitParser) processHeader(commit *Commit, input string) {
|
|||
commit.Mentions = p.parseMentions(input)
|
||||
|
||||
// Jira
|
||||
if commit.JiraIssueId != "" {
|
||||
p.processJiraIssue(commit, commit.JiraIssueId)
|
||||
if commit.JiraIssueID != "" {
|
||||
p.processJiraIssue(commit, commit.JiraIssueID)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,10 +364,10 @@ func (p *commitParser) uniqMentions(mentions []string) []string {
|
|||
return arr
|
||||
}
|
||||
|
||||
func (p *commitParser) processJiraIssue(commit *Commit, issueId string) {
|
||||
issue, err := p.jiraClient.GetJiraIssue(commit.JiraIssueId)
|
||||
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))
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func TestCommitParserParse(t *testing.T) {
|
|||
mock, nil, &Config{
|
||||
Options: &Options{
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"Type": {
|
||||
"feat",
|
||||
"fix",
|
||||
"perf",
|
||||
|
|
@ -79,7 +79,7 @@ func TestCommitParserParse(t *testing.T) {
|
|||
commits, err := parser.Parse("HEAD")
|
||||
assert.Nil(err)
|
||||
assert.Equal([]*Commit{
|
||||
&Commit{
|
||||
{
|
||||
Hash: &Hash{
|
||||
Long: "65cf1add9735dcc4810dda3312b0792236c97c4e",
|
||||
Short: "65cf1add",
|
||||
|
|
@ -97,7 +97,7 @@ func TestCommitParserParse(t *testing.T) {
|
|||
Merge: nil,
|
||||
Revert: nil,
|
||||
Refs: []*Ref{
|
||||
&Ref{
|
||||
{
|
||||
Action: "",
|
||||
Ref: "123",
|
||||
Source: "",
|
||||
|
|
@ -111,7 +111,7 @@ func TestCommitParserParse(t *testing.T) {
|
|||
Subject: "Add new feature #123",
|
||||
Body: "",
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Hash: &Hash{
|
||||
Long: "14ef0b6d386c5432af9292eab3c8314fa3001bc7",
|
||||
Short: "14ef0b6d",
|
||||
|
|
@ -132,24 +132,24 @@ func TestCommitParserParse(t *testing.T) {
|
|||
},
|
||||
Revert: nil,
|
||||
Refs: []*Ref{
|
||||
&Ref{
|
||||
{
|
||||
Action: "",
|
||||
Ref: "3",
|
||||
Source: "",
|
||||
},
|
||||
&Ref{
|
||||
{
|
||||
Action: "Fixes",
|
||||
Ref: "3",
|
||||
Source: "",
|
||||
},
|
||||
&Ref{
|
||||
{
|
||||
Action: "Closes",
|
||||
Ref: "1",
|
||||
Source: "",
|
||||
},
|
||||
},
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Title: "BREAKING CHANGE",
|
||||
Body: "This is breaking point message.",
|
||||
},
|
||||
|
|
@ -167,7 +167,7 @@ Closes #1
|
|||
|
||||
BREAKING CHANGE: This is breaking point message.`,
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Hash: &Hash{
|
||||
Long: "809a8280ffd0dadb0f4e7ba9fc835e63c37d6af6",
|
||||
Short: "809a8280",
|
||||
|
|
@ -201,7 +201,7 @@ BREAKING CHANGE: This is breaking point message.`,
|
|||
@hogefuga
|
||||
@FooBarBaz`,
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Hash: &Hash{
|
||||
Long: "74824d6bd1470b901ec7123d13a76a1b8938d8d0",
|
||||
Short: "74824d6b",
|
||||
|
|
@ -219,19 +219,19 @@ BREAKING CHANGE: This is breaking point message.`,
|
|||
Merge: nil,
|
||||
Revert: nil,
|
||||
Refs: []*Ref{
|
||||
&Ref{
|
||||
{
|
||||
Action: "Fixes",
|
||||
Ref: "123",
|
||||
Source: "",
|
||||
},
|
||||
&Ref{
|
||||
{
|
||||
Action: "Closes",
|
||||
Ref: "456",
|
||||
Source: "username/repository",
|
||||
},
|
||||
},
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Title: "BREAKING CHANGE",
|
||||
Body: fmt.Sprintf(`This is multiline breaking change note.
|
||||
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
|
||||
Closes username/repository#456`, "```", "```"),
|
||||
},
|
||||
&Commit{
|
||||
{
|
||||
Hash: &Hash{
|
||||
Long: "123456789735dcc4810dda3312b0792236c97c4e",
|
||||
Short: "12345678",
|
||||
|
|
@ -381,7 +381,7 @@ func TestCommitParserParseWithJira(t *testing.T) {
|
|||
mock, mockJiraClient{}, &Config{
|
||||
Options: &Options{
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"Type": {
|
||||
"feat",
|
||||
"fix",
|
||||
"perf",
|
||||
|
|
@ -391,7 +391,7 @@ func TestCommitParserParseWithJira(t *testing.T) {
|
|||
HeaderPattern: "^(?:(\\w*)|(?:\\[(.*)\\])?)\\:\\s(.*)$",
|
||||
HeaderPatternMaps: []string{
|
||||
"Type",
|
||||
"JiraIssueId",
|
||||
"JiraIssueID",
|
||||
"Subject",
|
||||
},
|
||||
JiraTypeMaps: map[string]string{
|
||||
|
|
@ -403,7 +403,7 @@ func TestCommitParserParseWithJira(t *testing.T) {
|
|||
commits, err := parser.Parse("HEAD")
|
||||
assert.Nil(err)
|
||||
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.Summary, "summary of JIRA-1111")
|
||||
assert.Equal(commit.JiraIssue.Description, "description of JIRA-1111")
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ func Example() {
|
|||
},
|
||||
Options: &Options{
|
||||
CommitFilters: map[string][]string{
|
||||
"Type": []string{
|
||||
"Type": {
|
||||
"feat",
|
||||
"fix",
|
||||
},
|
||||
|
|
|
|||
14
fields.go
14
fields.go
|
|
@ -52,7 +52,7 @@ type NoteGroup struct {
|
|||
Notes []*Note
|
||||
}
|
||||
|
||||
// JiraIssue
|
||||
// JiraIssue is information about a jira ticket (type, summary, description, and labels)
|
||||
type JiraIssue struct {
|
||||
Type string
|
||||
Summary string
|
||||
|
|
@ -69,13 +69,13 @@ type Commit struct {
|
|||
Revert *Revert // If it is not a revert commit, `nil` is assigned
|
||||
Refs []*Ref
|
||||
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
|
||||
Header string // (e.g. `feat(core)[RNWY-310]: Add new feature`)
|
||||
Type string // (e.g. `feat`)
|
||||
Scope string // (e.g. `core`)
|
||||
Subject string // (e.g. `Add new feature`)
|
||||
JiraIssueId string // (e.g. `RNWY-310`)
|
||||
Header string // (e.g. `feat(core)[RNWY-310]: Add new feature`)
|
||||
Type string // (e.g. `feat`)
|
||||
Scope string // (e.g. `core`)
|
||||
Subject string // (e.g. `Add new feature`)
|
||||
JiraIssueID string // (e.g. `RNWY-310`)
|
||||
Body string
|
||||
}
|
||||
|
||||
|
|
|
|||
6
jira.go
6
jira.go
|
|
@ -4,6 +4,7 @@ import (
|
|||
agjira "github.com/andygrunwald/go-jira"
|
||||
)
|
||||
|
||||
// JiraClient is an HTTP client for Jira
|
||||
type JiraClient interface {
|
||||
GetJiraIssue(id string) (*agjira.Issue, error)
|
||||
}
|
||||
|
|
@ -14,11 +15,12 @@ type jiraClient struct {
|
|||
url string
|
||||
}
|
||||
|
||||
// NewJiraClient returns an instance of JiraClient
|
||||
func NewJiraClient(config *Config) JiraClient {
|
||||
return jiraClient{
|
||||
username: config.Options.JiraUsername,
|
||||
token: config.Options.JiraToken,
|
||||
url: config.Options.JiraUrl,
|
||||
token: config.Options.JiraToken,
|
||||
url: config.Options.JiraURL,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
package chglog
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJira(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
config := &Config {
|
||||
config := &Config{
|
||||
Options: &Options{
|
||||
Processor: nil,
|
||||
NextTag: "",
|
||||
|
|
@ -29,7 +30,7 @@ func TestJira(t *testing.T) {
|
|||
NoteKeywords: nil,
|
||||
JiraUsername: "uuu",
|
||||
JiraToken: "ppp",
|
||||
JiraUrl: "http://jira.com",
|
||||
JiraURL: "http://jira.com",
|
||||
JiraTypeMaps: nil,
|
||||
JiraIssueDescriptionPattern: "",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/fatih/color"
|
||||
emoji "github.com/kyokomi/emoji/v2"
|
||||
"github.com/kyokomi/emoji/v2"
|
||||
)
|
||||
|
||||
// Logger ...
|
||||
|
|
@ -26,7 +26,7 @@ func NewLogger(stdout, stderr io.Writer, silent, noEmoji bool) *Logger {
|
|||
stderr: stderr,
|
||||
silent: silent,
|
||||
noEmoji: noEmoji,
|
||||
reEmoji: regexp.MustCompile(":[\\w\\+_\\-]+:\\s?"),
|
||||
reEmoji: regexp.MustCompile(`:[\w\+_\-]+:\s?`),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/stretchr/testify/assert"
|
||||
emoji "github.com/kyokomi/emoji/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLoggerLogSilent(t *testing.T) {
|
||||
|
|
@ -40,7 +40,7 @@ func TestLoggerLogNoEmoji(t *testing.T) {
|
|||
stderr := &bytes.Buffer{}
|
||||
logger := NewLogger(stdout, stderr, false, true)
|
||||
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) {
|
||||
|
|
|
|||
12
processor.go
12
processor.go
|
|
@ -33,8 +33,8 @@ func (p *GitHubProcessor) Bootstrap(config *Config) {
|
|||
p.Host = strings.TrimRight(p.Host, "/")
|
||||
}
|
||||
|
||||
p.reMention = regexp.MustCompile("@(\\w+)")
|
||||
p.reIssue = regexp.MustCompile("(?i)(#|gh-)(\\d+)")
|
||||
p.reMention = regexp.MustCompile(`@(\w+)`)
|
||||
p.reIssue = regexp.MustCompile(`(?i)(#|gh-)(\d+)`)
|
||||
}
|
||||
|
||||
// ProcessCommit ...
|
||||
|
|
@ -88,8 +88,8 @@ func (p *GitLabProcessor) Bootstrap(config *Config) {
|
|||
p.Host = strings.TrimRight(p.Host, "/")
|
||||
}
|
||||
|
||||
p.reMention = regexp.MustCompile("@(\\w+)")
|
||||
p.reIssue = regexp.MustCompile("(?i)#(\\d+)")
|
||||
p.reMention = regexp.MustCompile(`@(\w+)`)
|
||||
p.reIssue = regexp.MustCompile(`(?i)#(\d+)`)
|
||||
}
|
||||
|
||||
// ProcessCommit ...
|
||||
|
|
@ -143,8 +143,8 @@ func (p *BitbucketProcessor) Bootstrap(config *Config) {
|
|||
p.Host = strings.TrimRight(p.Host, "/")
|
||||
}
|
||||
|
||||
p.reMention = regexp.MustCompile("@(\\w+)")
|
||||
p.reIssue = regexp.MustCompile("(?i)#(\\d+)")
|
||||
p.reMention = regexp.MustCompile(`@(\w+)`)
|
||||
p.reIssue = regexp.MustCompile(`(?i)#(\d+)`)
|
||||
}
|
||||
|
||||
// ProcessCommit ...
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ func TestGitHubProcessor(t *testing.T) {
|
|||
multiline [#789](https://example.com/issues/789)
|
||||
[@foo](https://github.com/foo), [@bar](https://github.com/bar)`,
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Body: `issue1 [#11](https://example.com/issues/11)
|
||||
issue2 [#22](https://example.com/issues/22)
|
||||
[gh-56](https://example.com/issues/56) hoge fuga`,
|
||||
|
|
@ -42,7 +42,7 @@ issue2 [#22](https://example.com/issues/22)
|
|||
multiline #789
|
||||
@foo, @bar`,
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Body: `issue1 #11
|
||||
issue2 #22
|
||||
gh-56 hoge fuga`,
|
||||
|
|
@ -89,7 +89,7 @@ func TestGitLabProcessor(t *testing.T) {
|
|||
multiline [#789](https://example.com/issues/789)
|
||||
[@foo](https://gitlab.com/foo), [@bar](https://gitlab.com/bar)`,
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Body: `issue1 [#11](https://example.com/issues/11)
|
||||
issue2 [#22](https://example.com/issues/22)
|
||||
gh-56 hoge fuga`,
|
||||
|
|
@ -104,7 +104,7 @@ gh-56 hoge fuga`,
|
|||
multiline #789
|
||||
@foo, @bar`,
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Body: `issue1 #11
|
||||
issue2 #22
|
||||
gh-56 hoge fuga`,
|
||||
|
|
@ -151,7 +151,7 @@ func TestBitbucketProcessor(t *testing.T) {
|
|||
multiline [#789](https://example.com/issues/789/)
|
||||
[@foo](https://bitbucket.org/foo/), [@bar](https://bitbucket.org/bar/)`,
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Body: `issue1 [#11](https://example.com/issues/11/)
|
||||
issue2 [#22](https://example.com/issues/22/)
|
||||
gh-56 hoge fuga`,
|
||||
|
|
@ -166,7 +166,7 @@ gh-56 hoge fuga`,
|
|||
multiline #789
|
||||
@foo, @bar`,
|
||||
Notes: []*Note{
|
||||
&Note{
|
||||
{
|
||||
Body: `issue1 #11
|
||||
issue2 #22
|
||||
gh-56 hoge fuga`,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
type tagReader struct {
|
||||
client gitcmd.Client
|
||||
format string
|
||||
separator string
|
||||
reFilter *regexp.Regexp
|
||||
}
|
||||
|
|
@ -36,7 +35,7 @@ func (r *tagReader) ReadAll() ([]*Tag, error) {
|
|||
tags := []*Tag{}
|
||||
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func TestTagReader(t *testing.T) {
|
|||
|
||||
assert.Equal(
|
||||
[]*Tag{
|
||||
&Tag{
|
||||
{
|
||||
Name: "hoge_fuga",
|
||||
Subject: "Invalid semver tag name",
|
||||
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),
|
||||
},
|
||||
},
|
||||
&Tag{
|
||||
{
|
||||
Name: "5.0.0-rc.0",
|
||||
Subject: "Release 5.0.0-rc.0",
|
||||
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),
|
||||
},
|
||||
},
|
||||
&Tag{
|
||||
{
|
||||
Name: "4.4.4",
|
||||
Subject: "Release 4.4.4",
|
||||
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),
|
||||
},
|
||||
},
|
||||
&Tag{
|
||||
{
|
||||
Name: "4.4.3",
|
||||
Subject: "This is tag subject",
|
||||
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),
|
||||
},
|
||||
},
|
||||
&Tag{
|
||||
{
|
||||
Name: "v2.0.4-beta.1",
|
||||
Subject: "Release v2.0.4-beta.1",
|
||||
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
|
|
@ -104,11 +104,11 @@ func TestTagReader(t *testing.T) {
|
|||
actual,
|
||||
)
|
||||
|
||||
actual_filtered, err_filtered := newTagReader(client, "^v").ReadAll()
|
||||
assert.Nil(err_filtered)
|
||||
actualFiltered, errFiltered := newTagReader(client, "^v").ReadAll()
|
||||
assert.Nil(errFiltered)
|
||||
assert.Equal(
|
||||
[]*Tag{
|
||||
&Tag{
|
||||
{
|
||||
Name: "v2.0.4-beta.1",
|
||||
Subject: "Release v2.0.4-beta.1",
|
||||
Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
|
|
@ -116,6 +116,6 @@ func TestTagReader(t *testing.T) {
|
|||
Previous: nil,
|
||||
},
|
||||
},
|
||||
actual_filtered,
|
||||
actualFiltered,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,16 @@ func (s *tagSelector) Select(tags []*Tag, query string) ([]*Tag, string, error)
|
|||
case 2:
|
||||
old := tokens[0]
|
||||
new := tokens[1]
|
||||
if old == "" && new == "" {
|
||||
switch {
|
||||
case old == "" && new == "":
|
||||
return nil, "", nil
|
||||
} else if old == "" {
|
||||
case old == "":
|
||||
return s.selectBeforeTags(tags, new)
|
||||
} else if new == "" {
|
||||
case new == "":
|
||||
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
|
||||
|
|
@ -76,7 +78,8 @@ func (*tagSelector) selectBeforeTags(tags []*Tag, token string) ([]*Tag, string,
|
|||
}
|
||||
|
||||
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
|
||||
from string
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,51 +12,51 @@ func TestTagSelector(t *testing.T) {
|
|||
selector := newTagSelector()
|
||||
|
||||
fixtures := []*Tag{
|
||||
&Tag{Name: "2.2.12-rc.12"},
|
||||
&Tag{Name: "2.1.0"},
|
||||
&Tag{Name: "v2.0.0-beta.1"},
|
||||
&Tag{Name: "v1.2.9"},
|
||||
&Tag{Name: "v1.0.0"},
|
||||
{Name: "2.2.12-rc.12"},
|
||||
{Name: "2.1.0"},
|
||||
{Name: "v2.0.0-beta.1"},
|
||||
{Name: "v1.2.9"},
|
||||
{Name: "v1.0.0"},
|
||||
}
|
||||
|
||||
table := map[string][]string{
|
||||
// Single
|
||||
"2.2.12-rc.12": []string{
|
||||
"2.2.12-rc.12": {
|
||||
"2.2.12-rc.12",
|
||||
"2.1.0",
|
||||
},
|
||||
"v2.0.0-beta.1": []string{
|
||||
"v2.0.0-beta.1": {
|
||||
"v2.0.0-beta.1",
|
||||
"v1.2.9",
|
||||
},
|
||||
"v1.0.0": []string{
|
||||
"v1.0.0": {
|
||||
"v1.0.0",
|
||||
"",
|
||||
},
|
||||
// ~ <tag>
|
||||
"..2.1.0": []string{
|
||||
"..2.1.0": {
|
||||
"2.1.0",
|
||||
"v2.0.0-beta.1",
|
||||
"v1.2.9",
|
||||
"v1.0.0",
|
||||
"",
|
||||
},
|
||||
"..v1.0.0": []string{
|
||||
"..v1.0.0": {
|
||||
"v1.0.0",
|
||||
"",
|
||||
},
|
||||
// <tag> ~
|
||||
"v2.0.0-beta.1..": []string{
|
||||
"v2.0.0-beta.1..": {
|
||||
"2.2.12-rc.12",
|
||||
"2.1.0",
|
||||
"v2.0.0-beta.1",
|
||||
"v1.2.9",
|
||||
},
|
||||
"2.2.12-rc.12..": []string{
|
||||
"2.2.12-rc.12..": {
|
||||
"2.2.12-rc.12",
|
||||
"2.1.0",
|
||||
},
|
||||
"v1.0.0..": []string{
|
||||
"v1.0.0..": {
|
||||
"2.2.12-rc.12",
|
||||
"2.1.0",
|
||||
"v2.0.0-beta.1",
|
||||
|
|
@ -65,7 +65,7 @@ func TestTagSelector(t *testing.T) {
|
|||
"",
|
||||
},
|
||||
// <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.1.0",
|
||||
"v2.0.0-beta.1",
|
||||
|
|
@ -73,13 +73,13 @@ func TestTagSelector(t *testing.T) {
|
|||
"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",
|
||||
"v1.2.9",
|
||||
"v1.0.0",
|
||||
"",
|
||||
},
|
||||
"v1.2.9..2.1.0": []string{
|
||||
"v1.2.9..2.1.0": {
|
||||
"2.1.0",
|
||||
"v2.0.0-beta.1",
|
||||
"v1.2.9",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue