Skip to content

Commit

Permalink
feat: support version range. eg v2.0.0~v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
axetroy committed Nov 21, 2020
1 parent 6301c2f commit a65a4a8
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 71 deletions.
116 changes: 79 additions & 37 deletions internal/client/git.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"fmt"
"io"
"path"
"regexp"
Expand Down Expand Up @@ -200,66 +201,107 @@ func (g *GitClient) Logs(from string, to string) ([]*object.Commit, error) {
return commits, errors.WithStack(err)
}

func (g *GitClient) LogsAuto() ([]*object.Commit, error) {
var (
toHash string
)
// get commit hash from a string
// str: HEAD
// str: HASH
// str: tag
func (g *GitClient) getCommitHash(str string) (string, error) {
if str == "HEAD" {
commit, err := g.repository.Head()

head, err := g.repository.Head()
if err != nil {
return "", errors.WithStack(err)
}

return commit.Hash().String(), nil
} else {
version := versionRegexp.ReplaceAllString(str, "")
_, err := semver.New(version)

if err != nil {
return "", errors.WithStack(err)
}

tag, err := g.TagName(str)

if err != nil {
return "", errors.WithStack(err)
}

if tag == nil {
return "", errors.New(fmt.Sprintf(`tag '%s' not exist`, str))
}

return tag.Commit.Hash.String(), nil
}
}

func (g *GitClient) GetTagRangesByTagName(start string, end string) ([]*Tag, error) {
tags, err := g.Tags()

if err != nil {
return nil, errors.WithStack(err)
}

// get latest tag
tag, err := g.TagN(0)
startIndex := 0
endIndex := 0

for index, tag := range tags {
if tag.Name == start {
startIndex = index
} else if tag.Name == end {
endIndex = index
}
}

result := tags[startIndex : endIndex+1]

return result, nil
}

func (g *GitClient) GetTagRangesByCommitHash(startHash string, endHash string) ([]*Tag, error) {
start, err := g.repository.CommitObject(plumbing.NewHash(startHash))

if err != nil {
return nil, errors.WithStack(err)
}

// if tag not exist
if tag != nil {
toHash = tag.Commit.Hash.String()
end, err := g.repository.CommitObject(plumbing.NewHash(endHash))

// if head is latest tag's commit
if head.Hash().String() == toHash {
// get next tag
nextTag, err := g.TagN(1)
if err != nil {
return nil, errors.WithStack(err)
}

if err != nil {
return nil, errors.WithStack(err)
}
tags, err := g.Tags()

if nextTag != nil {
toHash = nextTag.Commit.Hash.String()
} else {
toHash = ""
}
if err != nil {
return nil, errors.WithStack(err)
}

result := make([]*Tag, 0)

for _, tag := range tags {
tagTime := tag.Commit.Committer.When
if tagTime.After(start.Author.When) && tagTime.After(end.Author.When) {
result = append(result, tag)
}
}

cIter, err := g.repository.Log(&git.LogOptions{From: head.Hash()})
return result, nil
}

func (g *GitClient) LogsRange(start string, end string) ([]*object.Commit, error) {
startHash, err := g.getCommitHash(start)

if err != nil {
return nil, errors.WithStack(err)
}

commits := make([]*object.Commit, 0)
endHash, err := g.getCommitHash(end)

for {
if commit, er := cIter.Next(); er == io.EOF {
break
} else if er != nil {
return nil, er
} else if commit == nil {
break
} else if commit.Hash.String() == toHash {
break
} else {
commits = append(commits, commit)
}
if err != nil {
return nil, errors.WithStack(err)
}

return commits, errors.WithStack(err)
return g.Logs(startHash, endHash)
}
29 changes: 29 additions & 0 deletions internal/printer/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package printer

import (
"bytes"
"html/template"
"strings"

"github.com/go-git/go-git/v5/plumbing/object"
"github.com/pkg/errors"
)

func Bytes(version string, commits []*object.Commit) ([]byte, error) {
ctx := transform(version, commits)

t := template.New("bytes")

t.Funcs(template.FuncMap{"StringsJoin": strings.Join})

if t, err := t.Parse(defaultTemplate); err != nil {
return nil, errors.WithStack(err)
} else {
b := bytes.NewBuffer([]byte{})
if err := t.Execute(b, ctx); err != nil {
return nil, errors.WithStack(err)
}

return b.Bytes(), nil
}
}
4 changes: 1 addition & 3 deletions internal/printer/stdout.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ func Stdout(version string, commits []*object.Commit) error {

t := template.New("stdout")

t.Funcs(template.FuncMap{
"StringsJoin": strings.Join,
})
t.Funcs(template.FuncMap{"StringsJoin": strings.Join})

if t, err := t.Parse(defaultTemplate); err != nil {
return errors.WithStack(err)
Expand Down
18 changes: 10 additions & 8 deletions internal/printer/template_default.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package printer

const defaultTemplate = `# {{ .Version }}
{{- define "body" -}}
{{range . -}}
- {{if .Field.Header.Scope }}**{{ .Field.Header.Scope }}**: {{ end }}{{ .Field.Header.Subject }}({{.Short}}) (thanks @{{ .Author.Name }}){{if .Field.Footer }} {{if .Field.Footer.Closes }}, Closes: {{ StringsJoin .Field.Footer.Closes "," }} {{- end }} {{- end}}
Expand All @@ -10,33 +11,34 @@ const defaultTemplate = `# {{ .Version }}
### New feature:
{{ template "body" .Feat }}
{{- end -}}
{{if .Fix -}}
{{if .Fix}}
### Bugs fixed:
{{ template "body" .Fix }}
{{- end -}}
{{if .Refactor -}}
{{if .Refactor}}
### Code Refactoring:
{{ template "body" .Refactor }}
{{- end -}}
{{if .Test -}}
{{if .Test}}
### Testing:
{{ template "body" .Test }}
{{- end -}}
{{if .Perf -}}
{{if .Perf}}
### Performance improves:
{{ template "body" .Perf }}
{{- end -}}
{{if .Docs -}}
{{if .Docs}}
### Documentation:
{{ template "body" .Docs }}
{{- end -}}
{{- if .BreakingChanges -}}
{{if .BreakingChanges}}
### BREAKING CHANGES:
{{ range .BreakingChanges -}}
- {{ .Field.Footer.BreakingChange.Title }} {{ .Field.Title }}
- {{if .Field.Footer.BreakingChange.Title}}{{ .Field.Footer.BreakingChange.Title }}{{ else }}{{ .Field.Title }}{{ end }}
{{ .Field.Footer.BreakingChange.Content }}
{{- end -}}
{{- end -}}
{{- end}}
### Commits({{ len .Commits }}):
{{range .Commits -}}
- **{{ .Short }}** {{ .Field.Title }}
Expand Down
102 changes: 79 additions & 23 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package main

import (
"bytes"
"flag"
"fmt"
"io"
"os"
"strings"

"github.com/axetroy/changelog/internal/client"
"github.com/axetroy/changelog/internal/printer"
Expand Down Expand Up @@ -173,38 +176,91 @@ func run() error {
}
}
} else {
// Only output one version of the changelog
from, err := client.TagName(version)
ranges := strings.Split(version, "~")
length := len(ranges)

if err != nil {
return errors.WithStack(err)
}
// handle version range
// v2.0.0~v1.0.0
// HEAD~
if length == 2 {
tags, err := client.GetTagRangesByTagName(ranges[0], ranges[1])

if from == nil {
return errors.New(fmt.Sprintf("can not found tag %s", version))
}
if err != nil {
return errors.WithStack(err)
}

to, err := client.NextTag(from)
var output []byte

if err != nil {
return errors.WithStack(err)
}
for index, tag := range tags {
fromHash := tag.Commit.Hash.String()
toHash := ""
// if not last element
if index != len(tags)-1 {
toHash = tags[index+1].Commit.Hash.String()
} else {
nextTag, err := client.NextTag(tag)

if err != nil {
return errors.WithStack(err)
}

if nextTag != nil {
toHash = nextTag.Commit.Hash.String()
}
}

toHash := ""
commits, err := client.Logs(fromHash, toHash)

// if don't have next tag
if to != nil {
toHash = to.Commit.Hash.String()
}
if err != nil {
return errors.WithStack(err)
}

commits, err := client.Logs(from.Commit.Hash.String(), toHash)
if b, err := printer.Bytes(tag.Name, commits); err != nil {
return errors.WithStack(err)
} else {
output = append(output, b...)
}
}

if err != nil {
return errors.WithStack(err)
}
_, err = io.Copy(os.Stdout, bytes.NewBuffer(output))

if err := printer.Stdout(version, commits); err != nil {
return errors.WithStack(err)
if err != nil {
return errors.WithStack(err)
}
} else {
// only output one version of the changelog
from, err := client.TagName(version)

if err != nil {
return errors.WithStack(err)
}

if from == nil {
return errors.New(fmt.Sprintf("can not found tag %s", version))
}

to, err := client.NextTag(from)

if err != nil {
return errors.WithStack(err)
}

toHash := ""

// if don't have next tag
if to != nil {
toHash = to.Commit.Hash.String()
}

commits, err := client.Logs(from.Commit.Hash.String(), toHash)

if err != nil {
return errors.WithStack(err)
}

if err := printer.Stdout(version, commits); err != nil {
return errors.WithStack(err)
}
}
}

Expand Down

0 comments on commit a65a4a8

Please sign in to comment.