generated from axetroy/go-cli-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Refactor the software architecture to make it clearer and s…
…impler
- Loading branch information
Showing
13 changed files
with
728 additions
and
342 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
package parser | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/axetroy/changelog/internal/client" | ||
"github.com/go-git/go-git/v5/plumbing/object" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type Range struct { | ||
*object.Commit | ||
*client.Tag | ||
} | ||
|
||
type Scope struct { | ||
Start Range // The range start | ||
End Range // The range end | ||
Tags []*client.Tag // Tags included in the range | ||
} | ||
|
||
var ( | ||
regShortHash = regexp.MustCompile(`^[a-z\d]{7}$`) | ||
regLongHash = regexp.MustCompile(`^[a-z\d]{40}$`) | ||
) | ||
|
||
func getCommitFromHEAD(git *client.GitClient) (*object.Commit, error) { | ||
ref, err := git.Head() | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
commit, err := git.Commit(ref.Hash().String()) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
return commit, err | ||
} | ||
|
||
func getCommit(git *client.GitClient, version string, isStart bool) (*object.Commit, error) { | ||
if version == "" { | ||
var ( | ||
commit *object.Commit | ||
err error | ||
) | ||
if isStart { | ||
// if version is a empty string, then it should be HEAD | ||
commit, err = getCommitFromHEAD(git) | ||
} else { | ||
// if version is a empty string, then it should be the first commit | ||
commit, err = git.GetFirstCommit() | ||
} | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
return commit, nil | ||
} else if version == "HEAD" { | ||
commit, err := getCommitFromHEAD(git) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
return commit, nil | ||
} else if regShortHash.MatchString(version) { | ||
return git.CommitByShort(version) | ||
} else if regLongHash.MatchString(version) { | ||
return git.Commit(version) | ||
} else { | ||
// else if it's a tag | ||
tag, err := git.TagName(version) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
if tag == nil { | ||
return nil, errors.New(fmt.Sprintf("tag '%s' not found", version)) | ||
} | ||
|
||
return tag.Commit, nil | ||
} | ||
} | ||
|
||
func Parse(git *client.GitClient, ranges string) (*Scope, error) { | ||
ranges = strings.TrimSpace(ranges) | ||
var ( | ||
startCommit *object.Commit | ||
endCommit *object.Commit | ||
scope = Scope{} | ||
err error | ||
) | ||
|
||
versions := strings.Split(ranges, "~") | ||
|
||
if ranges == "" { | ||
versions = append(versions, "HEAD") | ||
latestTag, err := git.TagN(0) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
if latestTag != nil { | ||
versions = append(versions, latestTag.Commit.Hash.String()) | ||
} else { | ||
versions = append(versions, "") | ||
} | ||
} else if len(versions) == 1 { | ||
// make sure the length is always 2 | ||
|
||
tag, err := git.TagName(ranges) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
if tag != nil { | ||
commit, err := git.GetLastCommitOfTag(tag) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
versions = append(versions, commit.Hash.String()) | ||
} else { | ||
versions = append(versions, "") | ||
} | ||
} | ||
|
||
if startCommit, err = getCommit(git, versions[0], true); err != nil { | ||
return nil, errors.WithStack(err) | ||
} else if startCommit == nil { | ||
return nil, errors.New(fmt.Sprintf("invalid version '%s'", versions[0])) | ||
} else { | ||
scope.Start = Range{Commit: startCommit} | ||
if tag, err := git.GetTagByCommit(startCommit); err != nil { | ||
return nil, errors.WithStack(err) | ||
} else if tag != nil { | ||
scope.Start.Tag = tag | ||
} | ||
} | ||
|
||
if endCommit, err = getCommit(git, versions[1], false); err != nil { | ||
return nil, errors.WithStack(err) | ||
} else if endCommit == nil { | ||
return nil, errors.New(fmt.Sprintf("invalid version '%s'", versions[1])) | ||
} else { | ||
scope.End = Range{Commit: endCommit} | ||
if tag, err := git.GetTagByCommit(endCommit); err != nil { | ||
return nil, errors.WithStack(err) | ||
} else if tag != nil { | ||
scope.End.Tag = tag | ||
|
||
lastCommitOfTag, err := git.GetLastCommitOfTag(tag) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
scope.End.Commit = lastCommitOfTag | ||
} | ||
} | ||
|
||
tags, err := git.GetTagRangesByCommit(startCommit, endCommit) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
scope.Tags = tags | ||
|
||
return &scope, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package extractor | ||
|
||
import ( | ||
"io" | ||
|
||
parser "github.com/axetroy/changelog/1_parser" | ||
"github.com/axetroy/changelog/internal/client" | ||
"github.com/go-git/go-git/v5" | ||
"github.com/go-git/go-git/v5/plumbing" | ||
"github.com/go-git/go-git/v5/plumbing/object" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type ExtractSplice struct { | ||
Name string // The name of splice | ||
Commit []*object.Commit // The commits including in this splice | ||
Tag *client.Tag // If this splice is a tag splice | ||
} | ||
|
||
func getTagOfCommit(tags []*client.Tag, commit *object.Commit) *client.Tag { | ||
for _, tag := range tags { | ||
if tag.Commit.Hash.String() == commit.Hash.String() { | ||
return tag | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func Extract(g *client.GitClient, scope *parser.Scope) ([]*ExtractSplice, error) { | ||
splices := make([]*ExtractSplice, 0) | ||
|
||
options := git.LogOptions{From: plumbing.NewHash(scope.Start.Commit.Hash.String())} | ||
|
||
cIter, err := g.Repository.Log(&options) | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
commits := make([]*object.Commit, 0) | ||
|
||
for { | ||
if commit, err := cIter.Next(); err == io.EOF { | ||
break | ||
} else if err != nil { | ||
return nil, errors.WithStack(err) | ||
} else if commit == nil { | ||
break | ||
} else if commit.Hash.String() == scope.End.Commit.Hash.String() { | ||
commits = append(commits, commit) | ||
break | ||
} else { | ||
commits = append(commits, commit) | ||
} | ||
} | ||
|
||
if err != nil { | ||
return nil, errors.WithStack(err) | ||
} | ||
|
||
// if there is no tags in this scope | ||
if scope.Tags == nil || len(scope.Tags) == 0 { | ||
splices = append(splices, &ExtractSplice{ | ||
Name: "Unreleased", | ||
Commit: commits, | ||
Tag: nil, | ||
}) | ||
|
||
return splices, nil | ||
} | ||
|
||
index := 0 | ||
|
||
splice := &ExtractSplice{ | ||
Name: "Unreleased", | ||
} | ||
|
||
for { | ||
if index == len(commits) { | ||
break | ||
} | ||
|
||
commit := commits[index] | ||
|
||
if tag := getTagOfCommit(scope.Tags, commit); tag != nil { | ||
if splice.Commit != nil { | ||
splices = append(splices, splice) | ||
} | ||
splice = &ExtractSplice{ | ||
Name: tag.Name, | ||
Tag: tag, | ||
} | ||
splices = append(splices, splice) | ||
} | ||
|
||
splice.Commit = append(splice.Commit, commit) | ||
|
||
index++ | ||
} | ||
|
||
return splices, nil | ||
} |
Oops, something went wrong.