1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-24 04:16:27 +02:00

211 lines
5.0 KiB
Go
Raw Normal View History

// Package changelog provides the release changelog to goreleaser.
package changelog
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"github.com/apex/log"
"github.com/goreleaser/goreleaser/internal/git"
2018-09-12 14:18:01 -03:00
"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 {
// TODO: should probably have a different field for the filename and its
// contents.
if ctx.ReleaseNotes != "" {
notes, err := loadFromFile(ctx.ReleaseNotes)
if err != nil {
return err
}
log.WithField("file", ctx.ReleaseNotes).Info("loaded custom release notes")
log.WithField("file", ctx.ReleaseNotes).Debugf("custom release notes: \n%s", notes)
ctx.ReleaseNotes = notes
}
if ctx.Config.Changelog.Skip {
return pipe.Skip("changelog should not be built")
}
if ctx.Snapshot {
2018-09-12 14:18:01 -03:00
return pipe.Skip("not available for snapshots")
}
if ctx.ReleaseNotes != "" {
return nil
}
if ctx.ReleaseHeader != "" {
header, err := loadFromFile(ctx.ReleaseHeader)
if err != nil {
return err
}
ctx.ReleaseHeader = header
}
if ctx.ReleaseFooter != "" {
footer, err := loadFromFile(ctx.ReleaseFooter)
if err != nil {
return err
}
ctx.ReleaseFooter = footer
}
if err := checkSortDirection(ctx.Config.Changelog.Sort); err != nil {
return err
}
entries, err := buildChangelog(ctx)
if err != nil {
return err
}
feat: add gitlab for releases (#1038) * outlines gitlab client integration * makes client parameter more explicit * adds gitlab url to config * changes releaseID to string to adapt to gitlab * updates to latest gitlab client lib 0.18 * fixes copy paster in gitlab upload func * fixes gitlab typo in config * adds gitlab token to env and context * release now uses the client factory method * skips brew pipe if it is not a github release * add github tokentype to publish tests * skips scoop pipe if it is not a github release * corrects brew skip msg * adds gitlab token to main test * adds gitlab to release docs * validates config and errors accordingly * adapt release pipe name to include gitlab * fixes gitlab client after testing * moves not-configured brew and scoop pipe checks as first check * adds more debug to gitlab client * adapts changelog generation for gitlab markdown * adds debug log for gitlab changelog * env needs to run before changelog pipe * moves gitlab default download url to default pipe * moves multiple releases check to from config to release pipe * release differs now for github and gitlab * adds debug gitlab release update msgs * moves env pipe as second after before because it determines the token type other pipes depend on * adaptes error check on gitlab release creation * Revert "adaptes error check on gitlab release creation" This reverts commit 032024571c76140f8e2207ee01cc08088f37594b. * simplifies gitlab client logic. removes comments * skips tls verification for gitlab client if specified in config * updates the docs * adds clarification that brew and scoop are not supported if it is a gitlab release * fixes copy paster in release.md * adds missing blob pipe in defaults and publish due to missing in merge * updates comment in gitlab client
2019-06-29 16:02:40 +02:00
changelogStringJoiner := "\n"
if ctx.TokenType == context.TokenTypeGitLab || ctx.TokenType == context.TokenTypeGitea {
// We need two or more whitespace to let markdown interpret
feat: add gitlab for releases (#1038) * outlines gitlab client integration * makes client parameter more explicit * adds gitlab url to config * changes releaseID to string to adapt to gitlab * updates to latest gitlab client lib 0.18 * fixes copy paster in gitlab upload func * fixes gitlab typo in config * adds gitlab token to env and context * release now uses the client factory method * skips brew pipe if it is not a github release * add github tokentype to publish tests * skips scoop pipe if it is not a github release * corrects brew skip msg * adds gitlab token to main test * adds gitlab to release docs * validates config and errors accordingly * adapt release pipe name to include gitlab * fixes gitlab client after testing * moves not-configured brew and scoop pipe checks as first check * adds more debug to gitlab client * adapts changelog generation for gitlab markdown * adds debug log for gitlab changelog * env needs to run before changelog pipe * moves gitlab default download url to default pipe * moves multiple releases check to from config to release pipe * release differs now for github and gitlab * adds debug gitlab release update msgs * moves env pipe as second after before because it determines the token type other pipes depend on * adaptes error check on gitlab release creation * Revert "adaptes error check on gitlab release creation" This reverts commit 032024571c76140f8e2207ee01cc08088f37594b. * simplifies gitlab client logic. removes comments * skips tls verification for gitlab client if specified in config * updates the docs * adds clarification that brew and scoop are not supported if it is a gitlab release * fixes copy paster in release.md * adds missing blob pipe in defaults and publish due to missing in merge * updates comment in gitlab client
2019-06-29 16:02:40 +02:00
// it as newline. See https://docs.gitlab.com/ee/user/markdown.html#newlines for details
log.Debug("is gitlab or gitea changelog")
feat: add gitlab for releases (#1038) * outlines gitlab client integration * makes client parameter more explicit * adds gitlab url to config * changes releaseID to string to adapt to gitlab * updates to latest gitlab client lib 0.18 * fixes copy paster in gitlab upload func * fixes gitlab typo in config * adds gitlab token to env and context * release now uses the client factory method * skips brew pipe if it is not a github release * add github tokentype to publish tests * skips scoop pipe if it is not a github release * corrects brew skip msg * adds gitlab token to main test * adds gitlab to release docs * validates config and errors accordingly * adapt release pipe name to include gitlab * fixes gitlab client after testing * moves not-configured brew and scoop pipe checks as first check * adds more debug to gitlab client * adapts changelog generation for gitlab markdown * adds debug log for gitlab changelog * env needs to run before changelog pipe * moves gitlab default download url to default pipe * moves multiple releases check to from config to release pipe * release differs now for github and gitlab * adds debug gitlab release update msgs * moves env pipe as second after before because it determines the token type other pipes depend on * adaptes error check on gitlab release creation * Revert "adaptes error check on gitlab release creation" This reverts commit 032024571c76140f8e2207ee01cc08088f37594b. * simplifies gitlab client logic. removes comments * skips tls verification for gitlab client if specified in config * updates the docs * adds clarification that brew and scoop are not supported if it is a gitlab release * fixes copy paster in release.md * adds missing blob pipe in defaults and publish due to missing in merge * updates comment in gitlab client
2019-06-29 16:02:40 +02:00
changelogStringJoiner = " \n"
}
ctx.ReleaseNotes = strings.Join(
[]string{
ctx.ReleaseHeader,
"## Changelog",
strings.Join(entries, changelogStringJoiner),
ctx.ReleaseFooter,
},
"\n\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 loadFromFile(file string) (string, error) {
bts, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
return string(bts), nil
}
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 {
var imsg = extractCommitInfo(result[i])
var 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 {
if !filter.MatchString(extractCommitInfo(entry)) {
result = append(result, entry)
}
}
return result
}
func extractCommitInfo(line string) string {
return strings.Join(strings.Split(line, " ")[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) {
2018-02-20 14:23:45 -03:00
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) {
if tag := os.Getenv("GORELEASER_PREVIOUS_TAG"); tag != "" {
return tag, nil
}
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
}
2018-11-07 22:04:49 -02:00
// nolint: gochecknoglobals
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)
}