test(*): add unit tests

This commit is contained in:
Nightapes
2019-07-21 15:07:13 +02:00
parent 69db52e5b1
commit 791983faae
12 changed files with 477 additions and 27 deletions

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@ go-semantic-release
.version .version
.vscode/settings.json .vscode/settings.json
CHANGELOG.md CHANGELOG.md
cover.html

View File

@@ -0,0 +1,37 @@
package commands
import (
"github.com/Nightapes/go-semantic-release/internal/ci"
"github.com/Nightapes/go-semantic-release/internal/gitutil"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(ciCmd)
}
var ciCmd = &cobra.Command{
Use: "ci",
Short: "ci configured artifact from release config",
RunE: func(cmd *cobra.Command, args []string) error {
repository, err := cmd.Flags().GetString("repository")
if err != nil {
return err
}
util, err := gitutil.New(repository)
if err != nil {
return err
}
config, err := ci.GetCIProvider(util, ci.ReadAllEnvs())
if err != nil {
return err
}
log.Infof("Found ci %v", config)
return nil
},
}

2
go.mod
View File

@@ -16,7 +16,7 @@ require (
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect
google.golang.org/appengine v1.6.1 // indirect google.golang.org/appengine v1.6.1 // indirect
gopkg.in/src-d/go-billy.v4 v4.3.1 // indirect gopkg.in/src-d/go-billy.v4 v4.3.1
gopkg.in/src-d/go-git.v4 v4.12.0 gopkg.in/src-d/go-git.v4 v4.12.0
gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 v2.2.2
) )

View File

@@ -15,11 +15,17 @@ type Analyzer struct {
Config config.ChangelogConfig Config config.ChangelogConfig
} }
//Release types, like major
type Release string
//Scope of the commit, like feat, fix,..
type Scope string
//Rule for commits //Rule for commits
type Rule struct { type Rule struct {
Tag string Tag string
TagString string TagString string
Release string Release Release
Changelog bool Changelog bool
} }
@@ -32,7 +38,7 @@ type analyzeCommit interface {
type AnalyzedCommit struct { type AnalyzedCommit struct {
Commit gitutil.Commit Commit gitutil.Commit
ParsedMessage string ParsedMessage string
Scope string Scope Scope
ParsedBreakingChangeMessage string ParsedBreakingChangeMessage string
Tag string Tag string
TagString string TagString string
@@ -62,9 +68,9 @@ func (a *Analyzer) GetRules() []Rule {
} }
// Analyze commits and return commits splitted by major,minor,patch // Analyze commits and return commits splitted by major,minor,patch
func (a *Analyzer) Analyze(commits []gitutil.Commit) map[string][]AnalyzedCommit { func (a *Analyzer) Analyze(commits []gitutil.Commit) map[Release][]AnalyzedCommit {
analyzedCommits := make(map[string][]AnalyzedCommit) analyzedCommits := make(map[Release][]AnalyzedCommit)
analyzedCommits["major"] = make([]AnalyzedCommit, 0) analyzedCommits["major"] = make([]AnalyzedCommit, 0)
analyzedCommits["minor"] = make([]AnalyzedCommit, 0) analyzedCommits["minor"] = make([]AnalyzedCommit, 0)
analyzedCommits["patch"] = make([]AnalyzedCommit, 0) analyzedCommits["patch"] = make([]AnalyzedCommit, 0)

View File

@@ -0,0 +1,16 @@
package analyzer_test
import (
"testing"
"github.com/Nightapes/go-semantic-release/internal/analyzer"
"github.com/Nightapes/go-semantic-release/pkg/config"
"github.com/stretchr/testify/assert"
)
func TestAnalyzer(t *testing.T) {
_, err := analyzer.New("unknown", config.ChangelogConfig{})
assert.Error(t, err)
}

View File

@@ -89,19 +89,19 @@ func (a *angular) analyze(commit gitutil.Commit, rule Rule) (AnalyzedCommit, boo
if len(matches) >= 1 { if len(matches) >= 1 {
if len(matches[0]) >= 3 { if len(matches[0]) >= 3 {
analyzed.Scope = matches[0][2] analyzed.Scope = Scope(matches[0][2])
message := strings.Join(matches[0][3:], "") message := strings.Join(matches[0][3:], "")
if !strings.Contains(message, "BREAKING CHANGE:") { if !strings.Contains(message, "BREAKING CHANGE:") {
analyzed.ParsedMessage = message analyzed.ParsedMessage = strings.Trim(message, " ")
log.Tracef("%s: found %s", commit.Message, rule.Tag) log.Tracef("%s: found %s", commit.Message, rule.Tag)
return analyzed, false, nil return analyzed, false, nil
} }
breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2) breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2)
analyzed.ParsedMessage = breakingChange[0] analyzed.ParsedMessage = strings.Trim(breakingChange[0], " ")
analyzed.ParsedBreakingChangeMessage = breakingChange[1] analyzed.ParsedBreakingChangeMessage = strings.Trim(breakingChange[1], " ")
log.Tracef(" %s, BREAKING CHANGE found", commit.Message) log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
return analyzed, true, nil return analyzed, true, nil

View File

@@ -0,0 +1,173 @@
package analyzer_test
import (
"testing"
"github.com/Nightapes/go-semantic-release/internal/analyzer"
"github.com/Nightapes/go-semantic-release/internal/gitutil"
"github.com/Nightapes/go-semantic-release/pkg/config"
"github.com/stretchr/testify/assert"
)
func TestAngular(t *testing.T) {
testConfigs := []struct {
testCase string
commits []gitutil.Commit
analyzedCommits map[analyzer.Release][]analyzer.AnalyzedCommit
}{
{
testCase: "feat",
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
"minor": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(internal/changelog): my first commit",
Author: "me",
Hash: "12345667",
},
Scope: "internal/changelog",
ParsedMessage: "my first commit",
Tag: "feat",
TagString: "Features",
Print: true,
},
},
"major": []analyzer.AnalyzedCommit{},
"patch": []analyzer.AnalyzedCommit{},
"none": []analyzer.AnalyzedCommit{},
},
commits: []gitutil.Commit{
gitutil.Commit{
Message: "feat(internal/changelog): my first commit",
Author: "me",
Hash: "12345667",
},
},
},
{
testCase: "feat breaking change",
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
"minor": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(internal/changelog): my first commit",
Author: "me",
Hash: "12345667",
},
Scope: "internal/changelog",
ParsedMessage: "my first commit",
Tag: "feat",
TagString: "Features",
Print: true,
},
},
"major": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
Author: "me",
Hash: "12345668",
},
Scope: "internal/changelog",
ParsedMessage: "my first break",
Tag: "feat",
TagString: "Features",
Print: true,
ParsedBreakingChangeMessage: "change api to v2",
},
},
"patch": []analyzer.AnalyzedCommit{},
"none": []analyzer.AnalyzedCommit{},
},
commits: []gitutil.Commit{
gitutil.Commit{
Message: "feat(internal/changelog): my first commit",
Author: "me",
Hash: "12345667",
},
gitutil.Commit{
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
Author: "me",
Hash: "12345668",
},
},
},
{
testCase: "invalid",
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
"minor": []analyzer.AnalyzedCommit{},
"major": []analyzer.AnalyzedCommit{},
"patch": []analyzer.AnalyzedCommit{},
"none": []analyzer.AnalyzedCommit{},
},
commits: []gitutil.Commit{
gitutil.Commit{
Message: "internal/changelog: my first commit",
Author: "me",
Hash: "12345667",
},
},
},
{
testCase: "feat and build",
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
"minor": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(internal/changelog): my first commit",
Author: "me",
Hash: "12345667",
},
Scope: "internal/changelog",
ParsedMessage: "my first commit",
Tag: "feat",
TagString: "Features",
Print: true,
},
},
"none": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "build(internal/changelog): my first build",
Author: "me",
Hash: "12345668",
},
Scope: "internal/changelog",
ParsedMessage: "my first build",
Tag: "build",
TagString: "Changes to CI/CD",
Print: false,
ParsedBreakingChangeMessage: "",
},
},
"patch": []analyzer.AnalyzedCommit{},
"major": []analyzer.AnalyzedCommit{},
},
commits: []gitutil.Commit{
gitutil.Commit{
Message: "feat(internal/changelog): my first commit",
Author: "me",
Hash: "12345667",
},
gitutil.Commit{
Message: "build(internal/changelog): my first build",
Author: "me",
Hash: "12345668",
},
},
},
}
angular, err := analyzer.New("angular", config.ChangelogConfig{})
assert.NoError(t, err)
for _, test := range testConfigs {
analyzedCommits := angular.Analyze(test.commits)
assert.Equalf(t, test.analyzedCommits["major"], analyzedCommits["major"], "Testcase %s should have major commits", test.testCase)
assert.Equalf(t, test.analyzedCommits["minor"], analyzedCommits["minor"], "Testcase %s should have minor commits", test.testCase)
assert.Equalf(t, test.analyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
assert.Equalf(t, test.analyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
}
}

70
internal/cache/cache_test.go vendored Normal file
View File

@@ -0,0 +1,70 @@
package cache_test
import (
"testing"
"github.com/Nightapes/go-semantic-release/internal/cache"
"github.com/stretchr/testify/assert"
"io/ioutil"
"os"
"path"
)
func TestReadCacheNotFound(t *testing.T) {
_, err := cache.Read("notfound/dir")
assert.Errorf(t, err, "Read non exsiting file")
}
func TestReadCacheInvalidContent(t *testing.T) {
dir, err := ioutil.TempDir("", "prefix")
assert.NoError(t, err)
defer os.RemoveAll(dir)
completePath := path.Join(path.Dir(dir), ".version")
brokenContent := []byte("hello broken\ngo: lang\n")
ioutil.WriteFile(completePath, brokenContent, 0644)
_, readError := cache.Read(dir)
assert.Errorf(t, readError, "Should give error, when broken content")
}
func TestWriteAndReadCache(t *testing.T) {
dir, err := ioutil.TempDir("", "prefix")
assert.NoError(t, err)
content := cache.ReleaseVersion{
Last: cache.ReleaseVersionEntry{
Commit: "12345",
Version: "1.0.0",
},
Next: cache.ReleaseVersionEntry{
Commit: "12346",
Version: "1.1.0",
},
Branch: "master",
Draft: true,
}
defer os.RemoveAll(dir)
writeError := cache.Write(dir, content)
assert.NoErrorf(t, writeError, "Should write file")
result, readError := cache.Read(dir)
assert.NoErrorf(t, readError, "Should read file")
assert.Equal(t, &content, result)
}
func TestWriteNotFound(t *testing.T) {
err := cache.Write("notfound/dir", cache.ReleaseVersion{})
assert.Errorf(t, err, "Write non exsiting file")
}

View File

@@ -0,0 +1,120 @@
package changelog_test
import (
"testing"
"github.com/Nightapes/go-semantic-release/internal/analyzer"
"github.com/Nightapes/go-semantic-release/internal/changelog"
"github.com/Nightapes/go-semantic-release/internal/gitutil"
"github.com/Nightapes/go-semantic-release/internal/shared"
"github.com/Nightapes/go-semantic-release/pkg/config"
"github.com/stretchr/testify/assert"
"time"
)
func TestChangelog(t *testing.T) {
templateConfig := shared.ChangelogTemplateConfig{
CommitURL: "https://commit.url",
CompareURL: "https://compare.url",
Hash: "hash",
Version: "1.0.0",
}
testConfigs := []struct {
testCase string
analyzedCommits map[analyzer.Release][]analyzer.AnalyzedCommit
result *shared.GeneratedChangelog
hasError bool
}{
{
testCase: "feat",
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
"minor": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(test): my first commit",
Author: "me",
Hash: "12345667",
},
Scope: "internal/changelog",
ParsedMessage: "my first commit",
Tag: "feat",
TagString: "Features",
Print: true,
},
},
},
result: &shared.GeneratedChangelog{
Title: "v1.0.0 (2019-07-19)",
Content: "# v1.0.0 (2019-07-19)\n\n ### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url)) \n\n ",
},
hasError: false,
},
{
testCase: "feat breaking change",
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
"minor": []analyzer.AnalyzedCommit{
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(test): my first commit",
Author: "me",
Hash: "12345667",
},
Scope: "internal/changelog",
ParsedMessage: "my first commit",
Tag: "feat",
TagString: "Features",
Print: true,
},
analyzer.AnalyzedCommit{
Commit: gitutil.Commit{
Message: "feat(test): my first break: BREAKING CHANGE: change api to v2",
Author: "me",
Hash: "12345668",
},
Scope: "internal/changelog",
ParsedMessage: "my first break",
Tag: "feat",
TagString: "Features",
Print: true,
ParsedBreakingChangeMessage: "change api to v2",
},
},
},
result: &shared.GeneratedChangelog{
Title: "v1.0.0 (2019-07-19)",
Content: "# v1.0.0 (2019-07-19)\n\n## BREAKING CHANGES\n\n* **`internal/changelog`** change api to v2 \nintroduced by commit: \nmy first break ([1234566](https://commit.url)) \n\n ### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url)) \n\n ",
},
hasError: false,
},
}
cl := changelog.New(&config.ReleaseConfig{}, []analyzer.Rule{
{
Tag: "feat",
TagString: "Features",
Release: "minor",
Changelog: true,
},
{
Tag: "fix",
TagString: "Bug fixes",
Release: "patch",
Changelog: true,
},
{
Tag: "build",
TagString: "Build",
Release: "none",
Changelog: false,
},
}, time.Date(2019, 7, 19, 0, 0, 0, 0, time.UTC))
for _, config := range testConfigs {
generatedChangelog, err := cl.GenerateChanglog(templateConfig, config.analyzedCommits)
assert.Equalf(t, config.hasError, err != nil, "Testcase %s should have error: %t -> %s", config.testCase, config.hasError, err)
assert.Equalf(t, config.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
}
}

View File

@@ -1,16 +1,49 @@
package ci_test package ci_test
import ( import (
"fmt"
"testing" "testing"
"time"
"github.com/Nightapes/go-semantic-release/internal/ci" "github.com/Nightapes/go-semantic-release/internal/ci"
"github.com/Nightapes/go-semantic-release/internal/gitutil" "github.com/Nightapes/go-semantic-release/internal/gitutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/src-d/go-billy.v4/memfs"
"gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/storage/memory" "gopkg.in/src-d/go-git.v4/storage/memory"
) )
func TestSum(t *testing.T) { func TestCi(t *testing.T) {
fs := memfs.New()
repository, err := git.Init(memory.NewStorage(), fs)
assert.NoError(t, err, "should open git repository")
file, err := fs.Create("README.md")
assert.NoError(t, err, "should create file")
w, err := repository.Worktree()
assert.NoError(t, err, "should get worktree")
w.Add(file.Name())
status, err := w.Status()
fmt.Println(status)
gitUtilInMemory := &gitutil.GitUtil{
Repository: repository,
}
newCommit, err := w.Commit("fix(test): add a commit", &git.CommitOptions{
Author: &object.Signature{
Name: "John Doe",
Email: "john@doe.org",
When: time.Now(),
},
})
testConfigs := []struct { testConfigs := []struct {
service string service string
envs map[string]string envs map[string]string
@@ -23,14 +56,14 @@ func TestSum(t *testing.T) {
result: nil, result: nil,
hasError: true, hasError: true,
}, },
// { {
// service: "Git", service: "Git",
// envs: map[string]string{ envs: map[string]string{
// "CI": "true", "CI": "true",
// }, },
// result: &ci.ProviderConfig{IsPR: true, PR: "10", PRBranch: "pr", Branch: "master", Tag: "TAG", Commit: "190bfd6aa60022afd0ef830342cfb07e33c45f37", BuildURL: "https://travis-ci.com/owner/repo/builds/1234", Service: "travis", Name: "Travis CI"}, result: &ci.ProviderConfig{IsPR: false, PR: "", PRBranch: "", Branch: "master", Tag: "", Commit: newCommit.String(), BuildURL: "", Service: "git", Name: "Git only"},
// hasError: false, hasError: false,
// }, },
{ {
service: "Travis PR", service: "Travis PR",
envs: map[string]string{ envs: map[string]string{
@@ -60,13 +93,6 @@ func TestSum(t *testing.T) {
}, },
} }
repository, err := git.Init(memory.NewStorage(), nil)
assert.NoError(t, err, "should open git repository")
gitUtilInMemory := &gitutil.GitUtil{
Repository: repository,
}
for _, config := range testConfigs { for _, config := range testConfigs {
provider, err := ci.GetCIProvider(gitUtilInMemory, config.envs) provider, err := ci.GetCIProvider(gitUtilInMemory, config.envs)
assert.Equalf(t, config.hasError, err != nil, "Service %s should have error: %t -> %s", config.service, config.hasError, err) assert.Equalf(t, config.hasError, err != nil, "Service %s should have error: %t -> %s", config.service, config.hasError, err)

View File

@@ -28,7 +28,7 @@ func (t Git) detect(envs map[string]string) (*ProviderConfig, error) {
} }
return &ProviderConfig{ return &ProviderConfig{
Service: "Git", Service: "git",
Name: "Git only", Name: "Git only",
Commit: hash, Commit: hash,
Branch: currentBranch, Branch: currentBranch,

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"strings" "strings"
"time"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/Nightapes/go-semantic-release/internal/analyzer" "github.com/Nightapes/go-semantic-release/internal/analyzer"
@@ -199,7 +200,7 @@ func (s *SemanticRelease) GetChangelog(releaseVersion *shared.ReleaseVersion) (*
log.Debugf("Found %d commits till last release", len(commits)) log.Debugf("Found %d commits till last release", len(commits))
c := changelog.New(s.config, s.analyzer.GetRules()) c := changelog.New(s.config, s.analyzer.GetRules(), time.Now())
return c.GenerateChanglog(shared.ChangelogTemplateConfig{ return c.GenerateChanglog(shared.ChangelogTemplateConfig{
Version: releaseVersion.Next.Version.String(), Version: releaseVersion.Next.Version.String(),
Hash: releaseVersion.Last.Commit, Hash: releaseVersion.Last.Commit,