mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-10 03:47:03 +02:00
6c79a6c51a
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.
152 lines
3.7 KiB
Go
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)
|
|
}
|