gitee.com/mirrors_opencollective/goreleaser@v0.45.0/pipeline/changelog/changelog.go (about) 1 // Package changelog provides the release changelog to goreleaser. 2 package changelog 3 4 import ( 5 "errors" 6 "fmt" 7 "regexp" 8 "sort" 9 "strings" 10 11 "github.com/goreleaser/goreleaser/context" 12 "github.com/goreleaser/goreleaser/internal/git" 13 "github.com/goreleaser/goreleaser/pipeline" 14 ) 15 16 // ErrInvalidSortDirection happens when the sort order is invalid 17 var ErrInvalidSortDirection = errors.New("invalid sort direction") 18 19 // Pipe for checksums 20 type Pipe struct{} 21 22 func (Pipe) String() string { 23 return "generating changelog" 24 } 25 26 // Run the pipe 27 func (Pipe) Run(ctx *context.Context) error { 28 if ctx.ReleaseNotes != "" { 29 return pipeline.Skip("release notes already provided via --release-notes") 30 } 31 if ctx.Snapshot { 32 return pipeline.Skip("not available for snapshots") 33 } 34 if err := checkSortDirection(ctx.Config.Changelog.Sort); err != nil { 35 return err 36 } 37 entries, err := buildChangelog(ctx) 38 if err != nil { 39 return err 40 } 41 ctx.ReleaseNotes = fmt.Sprintf("## Changelog\n\n%v", strings.Join(entries, "\n")) 42 return nil 43 } 44 45 func checkSortDirection(mode string) error { 46 switch mode { 47 case "": 48 fallthrough 49 case "asc": 50 fallthrough 51 case "desc": 52 return nil 53 } 54 return ErrInvalidSortDirection 55 } 56 57 func buildChangelog(ctx *context.Context) ([]string, error) { 58 log, err := getChangelog(ctx.Git.CurrentTag) 59 if err != nil { 60 return nil, err 61 } 62 var entries = strings.Split(log, "\n") 63 entries = entries[0 : len(entries)-1] 64 entries, err = filterEntries(ctx, entries) 65 if err != nil { 66 return entries, err 67 } 68 return sortEntries(ctx, entries), nil 69 } 70 71 func filterEntries(ctx *context.Context, entries []string) ([]string, error) { 72 for _, filter := range ctx.Config.Changelog.Filters.Exclude { 73 r, err := regexp.Compile(filter) 74 if err != nil { 75 return entries, err 76 } 77 entries = remove(r, entries) 78 } 79 return entries, nil 80 } 81 82 func sortEntries(ctx *context.Context, entries []string) []string { 83 var direction = ctx.Config.Changelog.Sort 84 if direction == "" { 85 return entries 86 } 87 var result = make([]string, len(entries)) 88 copy(result, entries) 89 sort.Slice(result, func(i, j int) bool { 90 _, imsg := extractCommitInfo(result[i]) 91 _, jmsg := extractCommitInfo(result[j]) 92 if direction == "asc" { 93 return strings.Compare(imsg, jmsg) < 0 94 } 95 return strings.Compare(imsg, jmsg) > 0 96 }) 97 return result 98 } 99 100 func remove(filter *regexp.Regexp, entries []string) (result []string) { 101 for _, entry := range entries { 102 _, msg := extractCommitInfo(entry) 103 if !filter.MatchString(msg) { 104 result = append(result, entry) 105 } 106 } 107 return result 108 } 109 110 func extractCommitInfo(line string) (hash, msg string) { 111 ss := strings.Split(line, " ") 112 return ss[0], strings.Join(ss[1:], " ") 113 } 114 115 func getChangelog(tag string) (string, error) { 116 prev, err := previous(tag) 117 if err != nil { 118 return "", err 119 } 120 if !prev.Tag { 121 return gitLog(prev.SHA, tag) 122 } 123 return gitLog(fmt.Sprintf("%v..%v", prev.SHA, tag)) 124 } 125 126 func gitLog(refs ...string) (string, error) { 127 var args = []string{"log", "--pretty=oneline", "--abbrev-commit", "--no-decorate"} 128 args = append(args, refs...) 129 return git.Run(args...) 130 } 131 132 func previous(tag string) (result ref, err error) { 133 result.Tag = true 134 result.SHA, err = git.Clean(git.Run("describe", "--tags", "--abbrev=0", tag+"^")) 135 if err != nil { 136 result.Tag = false 137 result.SHA, err = git.Clean(git.Run("rev-list", "--max-parents=0", "HEAD")) 138 } 139 return 140 } 141 142 type ref struct { 143 Tag bool 144 SHA string 145 }