releaser: Fix tag detection for changelog when doing a main release

Also improve the changelog slightly.

Fixes #3482
This commit is contained in:
Bjørn Erik Pedersen 2017-05-20 10:58:08 +03:00 committed by GitHub
parent a59525b05b
commit 4d1989d59c
5 changed files with 102 additions and 32 deletions

View file

@ -25,6 +25,7 @@ import (
var issueRe = regexp.MustCompile(`(?i)[Updates?|Closes?|Fix.*|See] #(\d+)`) var issueRe = regexp.MustCompile(`(?i)[Updates?|Closes?|Fix.*|See] #(\d+)`)
const ( const (
notesChanges = "notesChanges"
templateChanges = "templateChanges" templateChanges = "templateChanges"
coreChanges = "coreChanges" coreChanges = "coreChanges"
outChanges = "outChanges" outChanges = "outChanges"
@ -36,6 +37,7 @@ type changeLog struct {
Version string Version string
Enhancements map[string]gitInfos Enhancements map[string]gitInfos
Fixes map[string]gitInfos Fixes map[string]gitInfos
Notes gitInfos
All gitInfos All gitInfos
// Overall stats // Overall stats
@ -44,22 +46,25 @@ type changeLog struct {
ThemeCount int ThemeCount int
} }
func newChangeLog(infos gitInfos) changeLog { func newChangeLog(infos gitInfos) *changeLog {
return changeLog{ return &changeLog{
Enhancements: make(map[string]gitInfos), Enhancements: make(map[string]gitInfos),
Fixes: make(map[string]gitInfos), Fixes: make(map[string]gitInfos),
All: infos, All: infos,
} }
} }
func (l changeLog) addGitInfo(isFix bool, info gitInfo, category string) { func (l *changeLog) addGitInfo(isFix bool, info gitInfo, category string) {
var ( var (
infos gitInfos infos gitInfos
found bool found bool
segment map[string]gitInfos segment map[string]gitInfos
) )
if isFix { if category == notesChanges {
l.Notes = append(l.Notes, info)
return
} else if isFix {
segment = l.Fixes segment = l.Fixes
} else { } else {
segment = l.Enhancements segment = l.Enhancements
@ -74,7 +79,7 @@ func (l changeLog) addGitInfo(isFix bool, info gitInfo, category string) {
segment[category] = infos segment[category] = infos
} }
func gitInfosToChangeLog(infos gitInfos) changeLog { func gitInfosToChangeLog(infos gitInfos) *changeLog {
log := newChangeLog(infos) log := newChangeLog(infos)
for _, info := range infos { for _, info := range infos {
los := strings.ToLower(info.Subject) los := strings.ToLower(info.Subject)
@ -82,7 +87,9 @@ func gitInfosToChangeLog(infos gitInfos) changeLog {
var category = otherChanges var category = otherChanges
// TODO(bep) improve // TODO(bep) improve
if regexp.MustCompile("(?i)tpl:|tplimpl:|layout").MatchString(los) { if regexp.MustCompile("(?i)deprecate").MatchString(los) {
category = notesChanges
} else if regexp.MustCompile("(?i)tpl|tplimpl:|layout").MatchString(los) {
category = templateChanges category = templateChanges
} else if regexp.MustCompile("(?i)docs?:|documentation:").MatchString(los) { } else if regexp.MustCompile("(?i)docs?:|documentation:").MatchString(los) {
category = docsChanges category = docsChanges
@ -150,8 +157,8 @@ func git(args ...string) (string, error) {
return string(out), nil return string(out), nil
} }
func getGitInfos(remote bool) (gitInfos, error) { func getGitInfos(tag string, remote bool) (gitInfos, error) {
return getGitInfosBefore("HEAD", remote) return getGitInfosBefore("HEAD", tag, remote)
} }
type countribCount struct { type countribCount struct {
@ -207,11 +214,11 @@ func (g gitInfos) ContribCountPerAuthor() contribCounts {
return c return c
} }
func getGitInfosBefore(ref string, remote bool) (gitInfos, error) { func getGitInfosBefore(ref, tag string, remote bool) (gitInfos, error) {
var g gitInfos var g gitInfos
log, err := gitLogBefore(ref) log, err := gitLogBefore(ref, tag)
if err != nil { if err != nil {
return g, err return g, err
} }
@ -242,10 +249,16 @@ func getGitInfosBefore(ref string, remote bool) (gitInfos, error) {
// Ignore autogenerated commits etc. in change log. This is a regexp. // Ignore autogenerated commits etc. in change log. This is a regexp.
const ignoredCommits = "release:|vendor:|snapcraft:" const ignoredCommits = "release:|vendor:|snapcraft:"
func gitLogBefore(ref string) (string, error) { func gitLogBefore(ref, tag string) (string, error) {
prevTag, err := gitShort("describe", "--tags", "--abbrev=0", "--always", ref+"^") var prevTag string
if err != nil { var err error
return "", err if tag != "" {
prevTag = tag
} else {
prevTag, err = gitVersionTagBefore(ref)
if err != nil {
return "", err
}
} }
log, err := git("log", "-E", fmt.Sprintf("--grep=%s", ignoredCommits), "--invert-grep", "--pretty=format:%x1e%h%x1f%aE%x1f%s%x1f%b", "--abbrev-commit", prevTag+".."+ref) log, err := git("log", "-E", fmt.Sprintf("--grep=%s", ignoredCommits), "--invert-grep", "--pretty=format:%x1e%h%x1f%aE%x1f%s%x1f%b", "--abbrev-commit", prevTag+".."+ref)
if err != nil { if err != nil {
@ -255,11 +268,29 @@ func gitLogBefore(ref string) (string, error) {
return log, err return log, err
} }
func gitVersionTagBefore(ref string) (string, error) {
return gitShort("describe", "--tags", "--abbrev=0", "--always", "--match", "v[0-9]*", ref+"^")
}
func gitLog() (string, error) { func gitLog() (string, error) {
return gitLogBefore("HEAD") return gitLogBefore("HEAD", "")
} }
func gitShort(args ...string) (output string, err error) { func gitShort(args ...string) (output string, err error) {
output, err = git(args...) output, err = git(args...)
return strings.Replace(strings.Split(output, "\n")[0], "'", "", -1), err return strings.Replace(strings.Split(output, "\n")[0], "'", "", -1), err
} }
func tagExists(tag string) (bool, error) {
out, err := git("tag", "-l", tag)
if err != nil {
return false, err
}
if strings.Contains(out, tag) {
return true, nil
}
return false, nil
}

View file

@ -14,19 +14,15 @@
package releaser package releaser
import ( import (
"os"
"testing" "testing"
"runtime"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestGitInfos(t *testing.T) { func TestGitInfos(t *testing.T) {
if runtime.GOOS == "linux" { skipIfCI(t)
// Travis has an ancient git with no --invert-grep: https://github.com/travis-ci/travis-ci/issues/6328 infos, err := getGitInfos("v0.20", false)
t.Skip("Skip git test on Linux to make Travis happy.")
}
infos, err := getGitInfos(false)
require.NoError(t, err) require.NoError(t, err)
require.True(t, len(infos) > 0) require.True(t, len(infos) > 0)
@ -51,3 +47,30 @@ See #456
require.Equal(t, 543, issues[2]) require.Equal(t, 543, issues[2])
} }
func TestGitVersionTagBefore(t *testing.T) {
skipIfCI(t)
v1, err := gitVersionTagBefore("v0.18")
require.NoError(t, err)
require.Equal(t, "v0.17", v1)
}
func TestTagExists(t *testing.T) {
skipIfCI(t)
b1, err := tagExists("v0.18")
require.NoError(t, err)
require.True(t, b1)
b2, err := tagExists("adfagdsfg")
require.NoError(t, err)
require.False(t, b2)
}
func skipIfCI(t *testing.T) {
if os.Getenv("CI") != "" {
// Travis has an ancient git with no --invert-grep: https://github.com/travis-ci/travis-ci/issues/6328
// Also Travis clones very shallowly, making some of the tests above shaky.
t.Skip("Skip git test on Linux to make Travis happy.")
}
}

View file

@ -62,7 +62,10 @@ Hugo now has:
{{ with .ThemeCount }} {{ with .ThemeCount }}
* 156+ [themes](http://themes.gohugo.io/) * 156+ [themes](http://themes.gohugo.io/)
{{- end }} {{- end }}
{{ with .Notes }}
## Notes
{{ template "change-section" . }}
{{- end -}}
## Enhancements ## Enhancements
{{ template "change-headers" .Enhancements -}} {{ template "change-headers" .Enhancements -}}
## Fixes ## Fixes
@ -80,7 +83,7 @@ Hugo now has:
{{- end -}} {{- end -}}
{{- with $outChanges -}} {{- with $outChanges -}}
### Output ### Output
{{- template "change-section" . }} {{ template "change-section" . }}
{{- end -}} {{- end -}}
{{- with $coreChanges -}} {{- with $coreChanges -}}
### Core ### Core
@ -88,7 +91,7 @@ Hugo now has:
{{- end -}} {{- end -}}
{{- with $docsChanges -}} {{- with $docsChanges -}}
### Docs ### Docs
{{- template "change-section" . }} {{ template "change-section" . }}
{{- end -}} {{- end -}}
{{- with $otherChanges -}} {{- with $otherChanges -}}
### Other ### Other

View file

@ -18,6 +18,7 @@ package releaser
import ( import (
"bytes" "bytes"
"fmt"
"os" "os"
"testing" "testing"
@ -33,9 +34,11 @@ func _TestReleaseNotesWriter(t *testing.T) {
var b bytes.Buffer var b bytes.Buffer
// TODO(bep) consider to query GitHub directly for the gitlog with author info, probably faster. // TODO(bep) consider to query GitHub directly for the gitlog with author info, probably faster.
infos, err := getGitInfosBefore("v0.20", false) infos, err := getGitInfosBefore("HEAD", "v0.20", false)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, writeReleaseNotes("0.20", infos, &b)) require.NoError(t, writeReleaseNotes("0.21", infos, &b))
fmt.Println(b.String())
} }

View file

@ -24,7 +24,6 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings"
"github.com/spf13/hugo/helpers" "github.com/spf13/hugo/helpers"
) )
@ -89,20 +88,31 @@ func (r *ReleaseHandler) Run() error {
tag := "v" + version tag := "v" + version
// Exit early if tag already exists // Exit early if tag already exists
out, err := git("tag", "-l", tag) exists, err := tagExists(tag)
if err != nil { if err != nil {
return err return err
} }
if strings.Contains(out, tag) { if exists {
return fmt.Errorf("Tag %q already exists", tag) return fmt.Errorf("Tag %q already exists", tag)
} }
var changeLogFromTag string
if newVersion.PatchLevel == 0 {
// There may have been patch releases inbetween, so set the tag explicitly.
changeLogFromTag = "v" + newVersion.Prev().String()
exists, _ := tagExists(changeLogFromTag)
if !exists {
// fall back to one that exists.
changeLogFromTag = ""
}
}
var gitCommits gitInfos var gitCommits gitInfos
if r.shouldPrepare() || r.shouldRelease() { if r.shouldPrepare() || r.shouldRelease() {
gitCommits, err = getGitInfos(true) gitCommits, err = getGitInfos(changeLogFromTag, true)
if err != nil { if err != nil {
return err return err
} }