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

192 lines
4.4 KiB
Go
Raw Normal View History

2017-04-15 16:12:32 -03:00
// Package git implements the Pipe interface getting and validating the
// current git repository state
2017-01-14 12:34:22 -02:00
package git
2017-01-29 21:55:32 -02:00
import (
2017-04-29 12:49:22 +02:00
"bytes"
2017-04-15 17:04:26 -03:00
"fmt"
2017-01-30 08:08:42 -02:00
"regexp"
2017-01-29 21:55:32 -02:00
"strings"
2017-04-29 12:49:22 +02:00
"text/template"
2017-06-22 00:09:14 -03:00
"time"
2017-01-29 21:55:32 -02:00
2017-06-22 00:09:14 -03:00
"github.com/apex/log"
2017-01-29 21:55:32 -02:00
"github.com/goreleaser/goreleaser/context"
)
2017-01-14 12:34:22 -02:00
2017-01-30 08:08:42 -02:00
// ErrInvalidVersionFormat is return when the version isnt in a valid format
type ErrInvalidVersionFormat struct {
version string
}
func (e ErrInvalidVersionFormat) Error() string {
2017-04-15 17:04:26 -03:00
return fmt.Sprintf("%v is not in a valid version format", e.version)
2017-01-30 08:08:42 -02:00
}
2017-04-15 16:11:47 -03:00
// ErrDirty happens when the repo has uncommitted/unstashed changes
type ErrDirty struct {
status string
}
func (e ErrDirty) Error() string {
2017-04-15 17:04:26 -03:00
return fmt.Sprintf("git is currently in a dirty state:\n%v", e.status)
2017-04-15 16:11:47 -03:00
}
// ErrWrongRef happens when the HEAD reference is different from the tag being built
type ErrWrongRef struct {
2017-04-15 17:04:26 -03:00
commit, tag string
2017-04-15 16:11:47 -03:00
}
func (e ErrWrongRef) Error() string {
2017-04-15 17:04:26 -03:00
return fmt.Sprintf("git tag %v was not made against commit %v", e.tag, e.commit)
2017-04-15 16:11:47 -03:00
}
2017-04-29 12:49:22 +02:00
// ErrNoTag happens if the underlying git repository doesn't contain any tags
// but no snapshot-release was requested.
var ErrNoTag = fmt.Errorf("git doesn't contain any tags. Either add a tag or use --snapshot")
2017-01-14 12:34:22 -02:00
// Pipe for brew deployment
type Pipe struct{}
2017-01-14 19:41:32 +01:00
// Description of the pipe
2017-01-14 15:14:35 -02:00
func (Pipe) Description() string {
2017-04-15 16:11:47 -03:00
return "Getting and validating git state"
2017-01-14 12:34:22 -02:00
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
2017-04-19 17:05:10 -03:00
tag, commit, err := getInfo()
2017-01-14 12:34:22 -02:00
if err != nil {
return
}
2017-04-29 12:49:22 +02:00
if tag == "" && !ctx.Snapshot {
return ErrNoTag
}
2017-01-18 15:08:48 -02:00
ctx.Git = context.GitInfo{
2017-04-19 17:05:10 -03:00
CurrentTag: tag,
Commit: commit,
2017-01-14 14:06:57 -02:00
}
2017-05-01 10:39:57 -03:00
if err = setLog(ctx, tag, commit); err != nil {
return
2017-04-19 16:59:26 -03:00
}
2017-05-01 10:39:57 -03:00
if err = setVersion(ctx, tag, commit); err != nil {
return
}
if !ctx.Validate {
2017-06-22 10:47:34 -03:00
log.Warn("skipped validations because --skip-validate is set")
2017-05-01 10:39:57 -03:00
return nil
}
2017-05-01 10:57:37 -03:00
return validate(ctx, commit, tag)
2017-05-01 10:39:57 -03:00
}
func setVersion(ctx *context.Context, tag, commit string) (err error) {
if ctx.Snapshot {
2017-04-29 12:49:22 +02:00
snapshotName, err := getSnapshotName(ctx, tag, commit)
if err != nil {
2017-05-01 10:39:57 -03:00
return fmt.Errorf("failed to generate snapshot name: %s", err.Error())
2017-04-29 12:49:22 +02:00
}
ctx.Version = snapshotName
2017-05-01 10:39:57 -03:00
return nil
}
// removes usual `v` prefix
ctx.Version = strings.TrimPrefix(tag, "v")
return
}
func setLog(ctx *context.Context, tag, commit string) (err error) {
if ctx.ReleaseNotes != "" {
return
}
var log string
if tag == "" {
log, err = getChangelog(commit)
2017-04-29 12:49:22 +02:00
} else {
2017-05-01 10:39:57 -03:00
log, err = getChangelog(tag)
2017-04-29 12:49:22 +02:00
}
2017-05-01 10:39:57 -03:00
if err != nil {
return err
}
2017-05-01 10:39:57 -03:00
ctx.ReleaseNotes = fmt.Sprintf("## Changelog\n\n%v", log)
return nil
2017-04-29 12:49:22 +02:00
}
type snapshotNameData struct {
Commit string
Tag string
Timestamp int64
}
func getSnapshotName(ctx *context.Context, tag, commit string) (string, error) {
tmpl, err := template.New("snapshot").Parse(ctx.Config.Snapshot.NameTemplate)
var out bytes.Buffer
if err != nil {
return "", err
}
2017-05-01 10:39:57 -03:00
var data = snapshotNameData{
Commit: commit,
Tag: tag,
Timestamp: time.Now().Unix(),
2017-04-29 12:49:22 +02:00
}
2017-05-01 10:39:57 -03:00
err = tmpl.Execute(&out, data)
return out.String(), err
2017-04-15 17:04:26 -03:00
}
2017-05-01 10:57:37 -03:00
func validate(ctx *context.Context, commit, tag string) error {
2017-04-15 17:04:26 -03:00
out, err := git("status", "-s")
2017-04-15 16:11:47 -03:00
if strings.TrimSpace(out) != "" || err != nil {
return ErrDirty{out}
}
2017-05-01 10:57:37 -03:00
if ctx.Snapshot {
return nil
}
if !regexp.MustCompile("^[0-9.]+").MatchString(ctx.Version) {
return ErrInvalidVersionFormat{ctx.Version}
}
_, err = cleanGit("describe", "--exact-match", "--tags", "--match", tag)
if err != nil {
return ErrWrongRef{commit, tag}
2017-04-15 16:11:47 -03:00
}
return nil
2017-01-14 12:34:22 -02:00
}
2017-04-19 17:05:10 -03:00
func getChangelog(tag string) (string, error) {
prev, err := previous(tag)
if err != nil {
2017-04-19 17:05:10 -03:00
return "", err
2017-04-15 17:04:26 -03:00
}
2017-04-23 16:33:44 -03:00
if !prev.Tag {
return gitLog(prev.SHA, tag)
}
return gitLog(fmt.Sprintf("%v..%v", prev.SHA, tag))
}
func gitLog(refs ...string) (string, error) {
var args = []string{"log", "--pretty=oneline", "--abbrev-commit"}
args = append(args, refs...)
return git(args...)
2017-04-19 17:05:10 -03:00
}
func getInfo() (tag, commit string, err error) {
2017-04-23 16:33:44 -03:00
tag, err = cleanGit("describe", "--tags", "--abbrev=0")
2017-04-15 17:04:26 -03:00
if err != nil {
2017-06-22 10:47:34 -03:00
log.WithError(err).Info("failed to retrieve current tag")
2017-04-15 17:04:26 -03:00
}
commit, err = cleanGit("show", "--format='%H'", "HEAD")
return
}
2017-04-23 16:42:34 -03:00
func previous(tag string) (result ref, err error) {
result.Tag = true
result.SHA, err = cleanGit("describe", "--tags", "--abbrev=0", tag+"^")
2017-04-15 17:04:26 -03:00
if err != nil {
2017-04-23 16:42:34 -03:00
result.Tag = false
result.SHA, err = cleanGit("rev-list", "--max-parents=0", "HEAD")
}
2017-04-23 16:42:34 -03:00
return
2017-04-23 16:33:44 -03:00
}
type ref struct {
Tag bool
SHA string
}