mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-23 10:25:24 +00:00
Merge 5f46006783 into 83fc0386ad
This commit is contained in:
commit
ff337fe4b9
5 changed files with 625 additions and 4 deletions
|
|
@ -459,6 +459,13 @@ We have implemented the following custom template functions. These override func
|
|||
| `replace` | `func(s, old, new string, n int) string` | Replace `old` with `new` within string `s`, `n` times using `strings.Replace` |
|
||||
| `upperFirst` | `func(s string) string` | Upper case the first character of a string |
|
||||
|
||||
Following custom template functions are also available.
|
||||
|
||||
| Name | Signature | Description |
|
||||
| :------------------- | :---------------------------------------------------- | :---------------------------------------------------------------------------- |
|
||||
| `uniqueOlderCommits` | `func(commits []*Commit, fields ...string) []*Commit` | Removes duplicated commits. Duplication is evaluated with fields specified. If your logs are created with ".Scope" and ".Subject", specify "Scope" "Subject" to remove duplicated logs. Newer logs, that means ones coming upper in changelogs will be removed for duplication. |
|
||||
| `uniqueNewerCommits` | `func(commits []*Commit, fields ...string) []*Commit` | Removes duplicated commits just like `uniqueOlderCommits`, but older logs will be removed for duplication. |
|
||||
|
||||
If you are not satisfied with the prepared template please try customizing one.
|
||||
|
||||
---
|
||||
|
|
|
|||
105
chglog.go
105
chglog.go
|
|
@ -344,10 +344,12 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve
|
|||
// While Sprig provides these functions, they change the standard input
|
||||
// order which leads to a regression. For an example see:
|
||||
// https://github.com/Masterminds/sprig/blob/master/functions.go#L149
|
||||
"contains": strings.Contains,
|
||||
"hasPrefix": strings.HasPrefix,
|
||||
"hasSuffix": strings.HasSuffix,
|
||||
"replace": strings.Replace,
|
||||
"contains": strings.Contains,
|
||||
"hasPrefix": strings.HasPrefix,
|
||||
"hasSuffix": strings.HasSuffix,
|
||||
"replace": strings.Replace,
|
||||
"uniqueOlderCommits": uniqueOlderCommits,
|
||||
"uniqueNewerCommits": uniqueNewerCommits,
|
||||
}
|
||||
|
||||
fname := filepath.Base(gen.config.Template)
|
||||
|
|
@ -360,3 +362,98 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve
|
|||
Versions: versions,
|
||||
})
|
||||
}
|
||||
|
||||
// uniqueOlderCommits remmoves duplicated commits.
|
||||
// Newer commits are removed when duplicated.
|
||||
// Tests duplication with fields specified with `fields`.
|
||||
func uniqueOlderCommits(commits []*Commit, fields ...string) ([]*Commit, error) {
|
||||
if len(fields) == 0 {
|
||||
return nil, fmt.Errorf("specify at least one field")
|
||||
}
|
||||
if len(commits) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
filtered := make([]*Commit, 0, len(commits))
|
||||
for idx, commit := range commits {
|
||||
// compare with older commits and skip if duplicated.
|
||||
duplicated, err := hasDuplicatedCommit(commits[idx+1:], commit, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if duplicated {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, commit)
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// uniqueNewerCommits remmoves duplicated commits.
|
||||
// Older commits are removed when duplicated.
|
||||
// Tests duplication with fields specified with `fields`.
|
||||
func uniqueNewerCommits(commits []*Commit, fields ...string) ([]*Commit, error) {
|
||||
if len(fields) == 0 {
|
||||
return nil, fmt.Errorf("specify at least one field")
|
||||
}
|
||||
if len(commits) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
filtered := make([]*Commit, 0, len(commits))
|
||||
for idx, commit := range commits {
|
||||
// compare with newer commits and skip if duplicated.
|
||||
duplicated, err := hasDuplicatedCommit(commits[:idx], commit, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if duplicated {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, commit)
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func hasDuplicatedCommit(targetCommits []*Commit, commit *Commit, fields []string) (bool, error) {
|
||||
for _, targetCommit := range targetCommits {
|
||||
duplicated, err := isDuplicatedCommit(commit, targetCommit, fields)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if duplicated {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func isDuplicatedCommit(commit1 *Commit, commit2 *Commit, fields []string) (bool, error) {
|
||||
for _, field := range fields {
|
||||
a, ok := dotGetNilable(commit1, field)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("cannot extract field \"%v\" for commit \"%v\"", field, commit1.Hash.Short)
|
||||
}
|
||||
b, ok := dotGetNilable(commit2, field)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("cannot extract field \"%v\" for commit \"%v\"", field, commit1.Hash.Short)
|
||||
}
|
||||
// Here, `nil` for interface.
|
||||
if a == nil || b == nil {
|
||||
if a != nil || b != nil {
|
||||
// not duplicated ones if something differs.
|
||||
return false, nil
|
||||
}
|
||||
// considered to be same.
|
||||
continue
|
||||
}
|
||||
eq, err := compare(a, "==", b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !eq {
|
||||
// not duplicated ones if something differs.
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
// duplicated ones if nothing differs.
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
|||
472
chglog_test.go
472
chglog_test.go
|
|
@ -629,3 +629,475 @@ func TestGeneratorWithSprig(t *testing.T) {
|
|||
[2.0.0]: https://github.com/git-chglog/git-chglog/compare/1.0.0...2.0.0`, expected)
|
||||
|
||||
}
|
||||
|
||||
func TestUniqueOlderCommits(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
commits []*Commit
|
||||
fields []string
|
||||
expected []*Commit
|
||||
expectError assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "Duplication detected",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
// {Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "2 duplications detected",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
// {Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
// {Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "A double duplication detected",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
// {Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
// {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No duplicates",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No commits (empty)",
|
||||
commits: []*Commit{},
|
||||
fields: []string{"Subject"},
|
||||
expected: nil,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No commits (nil)",
|
||||
commits: nil,
|
||||
fields: []string{"Subject"},
|
||||
expected: nil,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Empty fields (error)",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{},
|
||||
expected: nil,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "nil for fields (error)",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: nil,
|
||||
expected: nil,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "bad field (error)",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{"NoSuchField"},
|
||||
expected: nil,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := uniqueOlderCommits(
|
||||
test.commits,
|
||||
test.fields...,
|
||||
)
|
||||
test.expectError(t, err)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUniqueNewerCommits(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
commits []*Commit
|
||||
fields []string
|
||||
expected []*Commit
|
||||
expectError assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "Duplication detected",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
// {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "2 duplications detected",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
// {Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated!
|
||||
// {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "A double duplication detected",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
// {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
// {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated!
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No duplicates",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{"Subject"},
|
||||
expected: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No commits (empty)",
|
||||
commits: []*Commit{},
|
||||
fields: []string{"Subject"},
|
||||
expected: nil,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No commits (nil)",
|
||||
commits: nil,
|
||||
fields: []string{"Subject"},
|
||||
expected: nil,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Empty fields (error)",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{},
|
||||
expected: nil,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "nil for fields (error)",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: nil,
|
||||
expected: nil,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "bad field (error)",
|
||||
commits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated!
|
||||
{Hash: &Hash{Short: "4"}, Subject: "log4"},
|
||||
},
|
||||
fields: []string{"NoSuchField"},
|
||||
expected: nil,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := uniqueNewerCommits(
|
||||
test.commits,
|
||||
test.fields...,
|
||||
)
|
||||
test.expectError(t, err)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasDuplicatedCommit(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
targetCommits []*Commit
|
||||
commit *Commit
|
||||
fields []string
|
||||
expected bool
|
||||
expectError assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "Duplication found",
|
||||
targetCommits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log2"},
|
||||
fields: []string{"Subject"},
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Duplication not found",
|
||||
targetCommits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log99"},
|
||||
fields: []string{"Subject"},
|
||||
expected: false,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No commits (empty)",
|
||||
targetCommits: []*Commit{},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"},
|
||||
fields: []string{"Subject"},
|
||||
expected: false,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "No commits (nil)",
|
||||
targetCommits: []*Commit{},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"},
|
||||
fields: []string{"Subject"},
|
||||
expected: false,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Empty fields: Nothing to compare and everything is duplicated",
|
||||
targetCommits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"},
|
||||
fields: []string{},
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "nil for fields: Nothing to compare and everything is duplicated",
|
||||
targetCommits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"},
|
||||
fields: nil,
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "bad field (error)",
|
||||
targetCommits: []*Commit{
|
||||
{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
{Hash: &Hash{Short: "3"}, Subject: "log3"},
|
||||
},
|
||||
commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"},
|
||||
fields: []string{"NoSuchField"},
|
||||
expected: false,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := hasDuplicatedCommit(
|
||||
test.targetCommits,
|
||||
test.commit,
|
||||
test.fields,
|
||||
)
|
||||
test.expectError(t, err)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDuplicatedCommit(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
commit1 *Commit
|
||||
commit2 *Commit
|
||||
fields []string
|
||||
expected bool
|
||||
expectError assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "Duplicated for single field",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log1"},
|
||||
fields: []string{"Subject"},
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Not duplicted for single field",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
fields: []string{"Subject"},
|
||||
expected: false,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Duplicated for multiple fields",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-1"},
|
||||
fields: []string{"Scope", "Subject", "JiraIssueID"},
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Not duplicted for multiple fields",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-2"},
|
||||
fields: []string{"Scope", "Subject", "JiraIssueID"},
|
||||
expected: false,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Nested",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1", Author: &Author{Name: "user1"}},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2", Author: &Author{Name: "user1"}},
|
||||
fields: []string{"Author.Name"},
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Nested: dereference nil",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1", Author: &Author{Name: "user1"}},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2", Author: nil},
|
||||
fields: []string{"Author.Name"},
|
||||
expected: false,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "Empty fields: Nothing to compare and everything is duplicated",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
fields: []string{},
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "nil for fields: Nothing to compare and everything is duplicated",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
fields: nil,
|
||||
expected: true,
|
||||
expectError: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "bad field (error)",
|
||||
commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"},
|
||||
commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"},
|
||||
fields: []string{"NoSuchField"},
|
||||
expected: false,
|
||||
expectError: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := isDuplicatedCommit(
|
||||
test.commit1,
|
||||
test.commit2,
|
||||
test.fields,
|
||||
)
|
||||
test.expectError(t, err)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
utils.go
18
utils.go
|
|
@ -8,6 +8,14 @@ import (
|
|||
)
|
||||
|
||||
func dotGet(target interface{}, prop string) (interface{}, bool) {
|
||||
return dotGetImpl(target, prop, false)
|
||||
}
|
||||
|
||||
func dotGetNilable(target interface{}, prop string) (interface{}, bool) {
|
||||
return dotGetImpl(target, prop, true)
|
||||
}
|
||||
|
||||
func dotGetImpl(target interface{}, prop string, nilable bool) (interface{}, bool) {
|
||||
path := strings.Split(prop, ".")
|
||||
|
||||
if len(path) == 0 {
|
||||
|
|
@ -18,6 +26,10 @@ func dotGet(target interface{}, prop string) (interface{}, bool) {
|
|||
var value reflect.Value
|
||||
|
||||
if reflect.TypeOf(target).Kind() == reflect.Ptr {
|
||||
if nilable && reflect.ValueOf(target).IsNil() {
|
||||
// avoid dereferencing nil.
|
||||
return nil, true
|
||||
}
|
||||
value = reflect.ValueOf(target).Elem()
|
||||
} else {
|
||||
value = reflect.ValueOf(target)
|
||||
|
|
@ -79,6 +91,8 @@ func compareString(a string, operator string, b string) bool {
|
|||
return a < b
|
||||
case ">":
|
||||
return a > b
|
||||
case "==":
|
||||
return a == b
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
@ -90,6 +104,8 @@ func compareInt(a int, operator string, b int) bool {
|
|||
return a < b
|
||||
case ">":
|
||||
return a > b
|
||||
case "==":
|
||||
return a == b
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
@ -101,6 +117,8 @@ func compareTime(a time.Time, operator string, b time.Time) bool {
|
|||
return !a.After(b)
|
||||
case ">":
|
||||
return a.After(b)
|
||||
case "==":
|
||||
return a.Equal(b)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,27 @@ func TestDotGet(t *testing.T) {
|
|||
assert.Nil(val)
|
||||
}
|
||||
|
||||
func TestDotGetNilable(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type Nest struct {
|
||||
Str string
|
||||
}
|
||||
|
||||
type Sample struct {
|
||||
Nest *Nest
|
||||
}
|
||||
|
||||
sample := Sample{
|
||||
Nest: nil,
|
||||
}
|
||||
|
||||
// Dereferencing nil
|
||||
val, ok := dotGetNilable(&sample, "Nest.Str")
|
||||
assert.True(ok)
|
||||
assert.Equal(val, nil)
|
||||
}
|
||||
|
||||
func TestCompare(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
|
|
@ -96,10 +117,16 @@ func TestCompare(t *testing.T) {
|
|||
{0, ">", 1, false},
|
||||
{1, ">", 0, true},
|
||||
{1, "<", 0, false},
|
||||
{0, "==", 1, false},
|
||||
{1, "==", 1, true},
|
||||
{"a", "<", "b", true},
|
||||
{"a", ">", "b", false},
|
||||
{"a", "==", "b", false},
|
||||
{"b", "==", "b", true},
|
||||
{time.Unix(1518018017, 0), "<", time.Unix(1518018043, 0), true},
|
||||
{time.Unix(1518018017, 0), ">", time.Unix(1518018043, 0), false},
|
||||
{time.Unix(1518018017, 0), "==", time.Unix(1518018043, 0), false},
|
||||
{time.Unix(1518018043, 0), "==", time.Unix(1518018043, 0), true},
|
||||
}
|
||||
|
||||
for _, sa := range table {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue