Skip to content

Commit

Permalink
refactor: extract commit analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
christophwitzko committed Aug 11, 2020
1 parent a8fe4ea commit 3b0c098
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 70 deletions.
6 changes: 5 additions & 1 deletion cmd/semantic-release/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"regexp"
"strings"

"github.com/go-semantic-release/semantic-release/pkg/analyzer/commit"
"github.com/go-semantic-release/semantic-release/pkg/condition"
"github.com/go-semantic-release/semantic-release/pkg/config"
"github.com/go-semantic-release/semantic-release/pkg/generator/changelog"
Expand Down Expand Up @@ -128,9 +129,12 @@ func cliHandler(c *cli.Context) error {
}

logger.Println("getting commits...")
commits, err := repo.GetCommits(currentSha)
rawCommits, err := repo.GetCommits(currentSha)
exitIfError(err)

commitAnalyzer := &commit.DefaultAnalyzer{}
commits := commitAnalyzer.Analyze(rawCommits)

logger.Println("calculating new version...")
newVer := semrel.GetNewVersion(conf, commits, release)
if newVer == nil {
Expand Down
44 changes: 44 additions & 0 deletions pkg/analyzer/commit/commit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package commit

import (
"regexp"
"strings"

"github.com/go-semantic-release/semantic-release/pkg/semrel"
)

type Analyzer interface {
Analyze([]*semrel.RawCommit) []*semrel.Commit
}

var commitPattern = regexp.MustCompile(`^(\w*)(?:\((.*)\))?\: (.*)$`)
var breakingPattern = regexp.MustCompile("BREAKING CHANGES?")

type DefaultAnalyzer struct{}

func (da *DefaultAnalyzer) analyzeSingleCommit(rawCommit *semrel.RawCommit) *semrel.Commit {
c := new(semrel.Commit)
c.SHA = rawCommit.SHA
c.Raw = strings.Split(rawCommit.RawMessage, "\n")
found := commitPattern.FindAllStringSubmatch(c.Raw[0], -1)
if len(found) < 1 {
return c
}
c.Type = strings.ToLower(found[0][1])
c.Scope = found[0][2]
c.Message = found[0][3]
c.Change = semrel.Change{
Major: breakingPattern.MatchString(rawCommit.RawMessage),
Minor: c.Type == "feat",
Patch: c.Type == "fix",
}
return c
}

func (da *DefaultAnalyzer) Analyze(rawCommits []*semrel.RawCommit) []*semrel.Commit {
ret := make([]*semrel.Commit, len(rawCommits))
for i, c := range rawCommits {
ret[i] = da.analyzeSingleCommit(c)
}
return ret
}
51 changes: 51 additions & 0 deletions pkg/analyzer/commit/commit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package commit

import (
"fmt"
"testing"

"github.com/go-semantic-release/semantic-release/pkg/semrel"
"github.com/stretchr/testify/require"
)

func compareCommit(c *semrel.Commit, t, s string, change semrel.Change) bool {
if c.Type != t || c.Scope != s {
return false
}
if c.Change.Major != change.Major ||
c.Change.Minor != change.Minor ||
c.Change.Patch != change.Patch {
return false
}
return true
}

func createRawCommit(sha, message string) *semrel.RawCommit {
return &semrel.RawCommit{
SHA: sha,
RawMessage: message,
}
}

func TestDefaultAnalyzer(t *testing.T) {
testCases := []struct {
RawCommit *semrel.RawCommit
Type string
Scope string
Change semrel.Change
}{
{
createRawCommit("a", "feat: new feature"),
"feat",
"",
semrel.Change{Major: false, Minor: true, Patch: false},
},
}

defaultAnalyzer := &DefaultAnalyzer{}
for _, tc := range testCases {
t.Run(fmt.Sprintf("AnalyzeCommitMessage: %s", tc.RawCommit.RawMessage), func(t *testing.T) {
require.True(t, compareCommit(defaultAnalyzer.analyzeSingleCommit(tc.RawCommit), tc.Type, tc.Scope, tc.Change))
})
}
}
9 changes: 6 additions & 3 deletions pkg/provider/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (repo *GitHubRepository) GetInfo() (*provider.RepositoryInfo, error) {
}, nil
}

func (repo *GitHubRepository) GetCommits(sha string) ([]*semrel.Commit, error) {
func (repo *GitHubRepository) GetCommits(sha string) ([]*semrel.RawCommit, error) {
opts := &github.CommitsListOptions{
SHA: sha,
ListOptions: github.ListOptions{PerPage: 100},
Expand All @@ -66,9 +66,12 @@ func (repo *GitHubRepository) GetCommits(sha string) ([]*semrel.Commit, error) {
if err != nil {
return nil, err
}
ret := make([]*semrel.Commit, len(commits))
ret := make([]*semrel.RawCommit, len(commits))
for i, commit := range commits {
ret[i] = semrel.NewCommit(commit.GetSHA(), commit.Commit.GetMessage())
ret[i] = &semrel.RawCommit{
SHA: commit.GetSHA(),
RawMessage: commit.Commit.GetMessage(),
}
}
return ret, nil
}
Expand Down
21 changes: 3 additions & 18 deletions pkg/provider/github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

"github.com/Masterminds/semver"
"github.com/go-semantic-release/semantic-release/pkg/provider"
"github.com/go-semantic-release/semantic-release/pkg/semrel"
"github.com/google/go-github/v30/github"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -136,30 +135,16 @@ func TestGithubGetInfo(t *testing.T) {
require.True(t, repoInfo.Private)
}

func compareCommit(c *semrel.Commit, t, s string, change semrel.Change) bool {
if c.Type != t || c.Scope != s {
return false
}
if c.Change.Major != change.Major ||
c.Change.Minor != change.Minor ||
c.Change.Patch != change.Patch {
return false
}
return true
}

func TestGithubGetCommits(t *testing.T) {
repo, ts := getNewGithubTestRepo(t)
defer ts.Close()
commits, err := repo.GetCommits("")
require.NoError(t, err)
require.Len(t, commits, 4)

if !compareCommit(commits[0], "feat", "app", semrel.Change{Major: false, Minor: true, Patch: false}) ||
!compareCommit(commits[1], "fix", "", semrel.Change{Major: false, Minor: false, Patch: true}) ||
!compareCommit(commits[2], "", "", semrel.Change{Major: false, Minor: false, Patch: false}) ||
!compareCommit(commits[3], "chore", "", semrel.Change{Major: true, Minor: false, Patch: false}) {
t.Fatal("invalid commits")
for i, c := range commits {
require.Equal(t, c.SHA, GITHUB_COMMITS[i].GetSHA())
require.Equal(t, c.RawMessage, GITHUB_COMMITS[i].Commit.GetMessage())
}
}

Expand Down
9 changes: 6 additions & 3 deletions pkg/provider/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (repo *GitLabRepository) GetInfo() (*provider.RepositoryInfo, error) {
}, nil
}

func (repo *GitLabRepository) GetCommits(sha string) ([]*semrel.Commit, error) {
func (repo *GitLabRepository) GetCommits(sha string) ([]*semrel.RawCommit, error) {
opts := &gitlab.ListCommitsOptions{
ListOptions: gitlab.ListOptions{
Page: 1,
Expand All @@ -72,7 +72,7 @@ func (repo *GitLabRepository) GetCommits(sha string) ([]*semrel.Commit, error) {
All: gitlab.Bool(true),
}

allCommits := make([]*semrel.Commit, 0)
allCommits := make([]*semrel.RawCommit, 0)

for {
commits, resp, err := repo.client.Commits.ListCommits(repo.projectID, opts)
Expand All @@ -82,7 +82,10 @@ func (repo *GitLabRepository) GetCommits(sha string) ([]*semrel.Commit, error) {
}

for _, commit := range commits {
allCommits = append(allCommits, semrel.NewCommit(commit.ID, commit.Message))
allCommits = append(allCommits, &semrel.RawCommit{
SHA: commit.ID,
RawMessage: commit.Message,
})
}

if resp.CurrentPage >= resp.TotalPages {
Expand Down
21 changes: 3 additions & 18 deletions pkg/provider/gitlab/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

"github.com/Masterminds/semver"
"github.com/go-semantic-release/semantic-release/pkg/provider"
"github.com/go-semantic-release/semantic-release/pkg/semrel"
"github.com/stretchr/testify/require"
"github.com/xanzy/go-gitlab"
)
Expand Down Expand Up @@ -125,30 +124,16 @@ func TestGitlabGetInfo(t *testing.T) {
require.True(t, repoInfo.Private)
}

func compareCommit(c *semrel.Commit, t, s string, change semrel.Change) bool {
if c.Type != t || c.Scope != s {
return false
}
if c.Change.Major != change.Major ||
c.Change.Minor != change.Minor ||
c.Change.Patch != change.Patch {
return false
}
return true
}

func TestGitlabGetCommits(t *testing.T) {
repo, ts := getNewGitlabTestRepo(t)
defer ts.Close()
commits, err := repo.GetCommits("")
require.NoError(t, err)
require.Len(t, commits, 4)

if !compareCommit(commits[0], "feat", "app", semrel.Change{Major: false, Minor: true, Patch: false}) ||
!compareCommit(commits[1], "fix", "", semrel.Change{Major: false, Minor: false, Patch: true}) ||
!compareCommit(commits[2], "", "", semrel.Change{Major: false, Minor: false, Patch: false}) ||
!compareCommit(commits[3], "chore", "", semrel.Change{Major: true, Minor: false, Patch: false}) {
t.Fatal("invalid commits")
for i, c := range commits {
require.Equal(t, c.SHA, GITLAB_COMMITS[i].ID)
require.Equal(t, c.RawMessage, GITLAB_COMMITS[i].Message)
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/provider/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type RepositoryRelease struct {

type Repository interface {
GetInfo() (*RepositoryInfo, error)
GetCommits(sha string) ([]*semrel.Commit, error)
GetCommits(sha string) ([]*semrel.RawCommit, error)
GetReleases(re *regexp.Regexp) (semrel.Releases, error)
CreateRelease(*RepositoryRelease) error
Provider() string
Expand Down
30 changes: 4 additions & 26 deletions pkg/semrel/commit.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package semrel

import (
"regexp"
"strings"
)

var commitPattern = regexp.MustCompile(`^(\w*)(?:\((.*)\))?\: (.*)$`)
var breakingPattern = regexp.MustCompile("BREAKING CHANGES?")
type RawCommit struct {
SHA string
RawMessage string
}

type Change struct {
Major, Minor, Patch bool
Expand All @@ -20,22 +17,3 @@ type Commit struct {
Message string
Change Change
}

func NewCommit(sha, msg string) *Commit {
c := new(Commit)
c.SHA = sha
c.Raw = strings.Split(msg, "\n")
found := commitPattern.FindAllStringSubmatch(c.Raw[0], -1)
if len(found) < 1 {
return c
}
c.Type = strings.ToLower(found[0][1])
c.Scope = found[0][2]
c.Message = found[0][3]
c.Change = Change{
Major: breakingPattern.MatchString(msg),
Minor: c.Type == "feat",
Patch: c.Type == "fix",
}
return c
}

0 comments on commit 3b0c098

Please sign in to comment.