1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-10 03:47:03 +02:00
goreleaser/internal/pipe/changelog/changelog.go
Alan Scherger 6c79a6c51a fix: be explicit when we query git for tags
When Jenkins is configured with 'Check out to matching local branch' the branch and tag name will conflict.
If we use explicit references to tags, then life is much better.

This patch also replaces our manual 'tag or not' boolean with a regex to check if the return is a SHA1.
If it is not a SHA1, it is assumed to be a tag. Hopefully this helps with future maintainability.
2018-10-06 22:21:46 -03:00

152 lines
3.7 KiB
Go

// Package changelog provides the release changelog to goreleaser.
package changelog
import (
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"regexp"
"sort"
"strings"
"github.com/apex/log"
"github.com/goreleaser/goreleaser/internal/git"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/pkg/context"
)
// ErrInvalidSortDirection happens when the sort order is invalid
var ErrInvalidSortDirection = errors.New("invalid sort direction")
// Pipe for checksums
type Pipe struct{}
func (Pipe) String() string {
return "generating changelog"
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
if ctx.ReleaseNotes != "" {
return pipe.Skip("release notes already provided via --release-notes")
}
if ctx.Snapshot {
return pipe.Skip("not available for snapshots")
}
if err := checkSortDirection(ctx.Config.Changelog.Sort); err != nil {
return err
}
entries, err := buildChangelog(ctx)
if err != nil {
return err
}
ctx.ReleaseNotes = fmt.Sprintf("## Changelog\n\n%v\n", strings.Join(entries, "\n"))
var path = filepath.Join(ctx.Config.Dist, "CHANGELOG.md")
log.WithField("changelog", path).Info("writing")
return ioutil.WriteFile(path, []byte(ctx.ReleaseNotes), 0644)
}
func checkSortDirection(mode string) error {
switch mode {
case "":
fallthrough
case "asc":
fallthrough
case "desc":
return nil
}
return ErrInvalidSortDirection
}
func buildChangelog(ctx *context.Context) ([]string, error) {
log, err := getChangelog(ctx.Git.CurrentTag)
if err != nil {
return nil, err
}
var entries = strings.Split(log, "\n")
entries = entries[0 : len(entries)-1]
entries, err = filterEntries(ctx, entries)
if err != nil {
return entries, err
}
return sortEntries(ctx, entries), nil
}
func filterEntries(ctx *context.Context, entries []string) ([]string, error) {
for _, filter := range ctx.Config.Changelog.Filters.Exclude {
r, err := regexp.Compile(filter)
if err != nil {
return entries, err
}
entries = remove(r, entries)
}
return entries, nil
}
func sortEntries(ctx *context.Context, entries []string) []string {
var direction = ctx.Config.Changelog.Sort
if direction == "" {
return entries
}
var result = make([]string, len(entries))
copy(result, entries)
sort.Slice(result, func(i, j int) bool {
_, imsg := extractCommitInfo(result[i])
_, jmsg := extractCommitInfo(result[j])
if direction == "asc" {
return strings.Compare(imsg, jmsg) < 0
}
return strings.Compare(imsg, jmsg) > 0
})
return result
}
func remove(filter *regexp.Regexp, entries []string) (result []string) {
for _, entry := range entries {
_, msg := extractCommitInfo(entry)
if !filter.MatchString(msg) {
result = append(result, entry)
}
}
return result
}
func extractCommitInfo(line string) (hash, msg string) {
ss := strings.Split(line, " ")
return ss[0], strings.Join(ss[1:], " ")
}
func getChangelog(tag string) (string, error) {
prev, err := previous(tag)
if err != nil {
return "", err
}
if isSHA1(prev) {
return gitLog(prev, tag)
}
return gitLog(fmt.Sprintf("tags/%s..tags/%s", prev, tag))
}
func gitLog(refs ...string) (string, error) {
var args = []string{"log", "--pretty=oneline", "--abbrev-commit", "--no-decorate", "--no-color"}
args = append(args, refs...)
return git.Run(args...)
}
func previous(tag string) (result string, err error) {
result, err = git.Clean(git.Run("describe", "--tags", "--abbrev=0", fmt.Sprintf("tags/%s^", tag)))
if err != nil {
result, err = git.Clean(git.Run("rev-list", "--max-parents=0", "HEAD"))
}
return
}
var validSHA1 = regexp.MustCompile(`^[a-fA-F0-9]{40}$`)
// isSHA1 te lets us know if the ref is a SHA1 or not
func isSHA1(ref string) bool {
return validSHA1.MatchString(ref)
}