Skip to content

Commit

Permalink
refactor: Refactor the software architecture to make it clearer and s…
Browse files Browse the repository at this point in the history
…impler
  • Loading branch information
axetroy committed Nov 22, 2020
1 parent 66bcf8f commit 0b6ba0c
Show file tree
Hide file tree
Showing 13 changed files with 728 additions and 342 deletions.
181 changes: 181 additions & 0 deletions 1_parser/parser.go
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
}
103 changes: 103 additions & 0 deletions 2_extractor/extractor.go
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
}
Loading

0 comments on commit 0b6ba0c

Please sign in to comment.