diff --git a/client/client.go b/client/client.go index 0554d624a..12e7af1c4 100644 --- a/client/client.go +++ b/client/client.go @@ -4,7 +4,6 @@ package client import ( "bytes" "os" - "os/exec" "github.com/goreleaser/goreleaser/context" ) @@ -19,17 +18,7 @@ type Info struct { // Client interface type Client interface { GetInfo(ctx *context.Context) (info Info, err error) - CreateRelease(ctx *context.Context) (releaseID int, err error) + CreateRelease(ctx *context.Context, body string) (releaseID int, err error) CreateFile(ctx *context.Context, content bytes.Buffer, path string) (err error) Upload(ctx *context.Context, releaseID int, name string, file *os.File) (err error) } - -func describeRelease(diff string) string { - result := "## Changelog\n" + diff + "\n\n--\nAutomated with @goreleaser" - cmd := exec.Command("go", "version") - bts, err := cmd.CombinedOutput() - if err != nil { - return result - } - return result + "\nBuilt with " + string(bts) -} diff --git a/client/client_test.go b/client/client_test.go index 102834726..47cd800bd 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1,15 +1,10 @@ package client -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDescription(t *testing.T) { - assert := assert.New(t) - desc := describeRelease("0abf342 some message") - assert.Contains(desc, "0abf342 some message") - assert.Contains(desc, "Automated with @goreleaser") - assert.Contains(desc, "go version go1.") -} +// TODO fix this +// func TestDescription(t *testing.T) { +// assert := assert.New(t) +// desc := describeRelease("0abf342 some message") +// assert.Contains(desc, "0abf342 some message") +// assert.Contains(desc, "Automated with @goreleaser") +// assert.Contains(desc, "go version go1.") +// } diff --git a/client/github.go b/client/github.go index ce90260e1..5829becf4 100644 --- a/client/github.go +++ b/client/github.go @@ -88,11 +88,11 @@ func (c *githubClient) GetInfo(ctx *context.Context) (info Info, err error) { return } -func (c *githubClient) CreateRelease(ctx *context.Context) (releaseID int, err error) { +func (c *githubClient) CreateRelease(ctx *context.Context, body string) (releaseID int, err error) { data := &github.RepositoryRelease{ Name: github.String(ctx.Git.CurrentTag), TagName: github.String(ctx.Git.CurrentTag), - Body: github.String(describeRelease(ctx.Git.Diff)), + Body: github.String(body), } r, _, err := c.client.Repositories.GetReleaseByTag( ctx, diff --git a/context/context.go b/context/context.go index 91be7f2c8..079aa76b0 100644 --- a/context/context.go +++ b/context/context.go @@ -19,7 +19,6 @@ import ( type GitInfo struct { CurrentTag string PreviousTag string - Diff string Commit string } @@ -31,6 +30,7 @@ type Context struct { Git GitInfo Archives map[string]string Artifacts []string + Changelog string Version string Validate bool Publish bool diff --git a/main.go b/main.go index 04b7ff854..c110e2efa 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "io/ioutil" "log" "os" @@ -52,6 +53,10 @@ func main() { Usage: "Load configuration from `FILE`", Value: "goreleaser.yml", }, + cli.StringFlag{ + Name: "release-notes", + Usage: "Define a file with custom release notes to be used instead of the git log between tags", + }, cli.BoolFlag{ Name: "skip-validate", Usage: "Skip all the validations against the release", @@ -63,6 +68,7 @@ func main() { } app.Action = func(c *cli.Context) (err error) { var file = c.String("config") + var notes = c.String("release-notes") cfg, err := config.Load(file) if err != nil { // Allow file not found errors if config file was not @@ -75,6 +81,13 @@ func main() { var ctx = context.New(cfg) ctx.Validate = !c.Bool("skip-validate") ctx.Publish = !c.Bool("skip-publish") + if notes != "" { + bts, err := ioutil.ReadFile(notes) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + ctx.Changelog = string(bts) + } for _, pipe := range pipes { log.Println(pipe.Description()) log.SetPrefix(" -> ") diff --git a/pipeline/git/git.go b/pipeline/git/git.go index 0255846e5..d07feef3c 100644 --- a/pipeline/git/git.go +++ b/pipeline/git/git.go @@ -47,16 +47,22 @@ func (Pipe) Description() string { // Run the pipe func (Pipe) Run(ctx *context.Context) (err error) { - tag, prev, commit, log, err := getInfo() + tag, prev, commit, err := getInfo() if err != nil { return } ctx.Git = context.GitInfo{ CurrentTag: tag, PreviousTag: prev, - Diff: log, Commit: commit, } + if ctx.Changelog == "" { + log, err := git("log", "--pretty=oneline", "--abbrev-commit", prev+".."+tag) + if err != nil { + return err + } + ctx.Changelog = log + } // removes usual `v` prefix ctx.Version = strings.TrimPrefix(tag, "v") if !ctx.Validate { @@ -81,7 +87,7 @@ func validate(commit, tag, version string) error { return nil } -func getInfo() (tag, prev, commit, log string, err error) { +func getInfo() (tag, prev, commit string, err error) { tag, err = cleanGit("describe", "--tags", "--abbrev=0", "--always") if err != nil { return @@ -90,10 +96,6 @@ func getInfo() (tag, prev, commit, log string, err error) { if err != nil { return } - log, err = git("log", "--pretty=oneline", "--abbrev-commit", prev+".."+tag) - if err != nil { - return - } commit, err = cleanGit("show", "--format='%H'", "HEAD") return } diff --git a/pipeline/release/body.go b/pipeline/release/body.go new file mode 100644 index 000000000..3a8d4da0a --- /dev/null +++ b/pipeline/release/body.go @@ -0,0 +1,34 @@ +package release + +import ( + "bytes" + "html/template" + "os/exec" + + "github.com/goreleaser/goreleaser/context" +) + +const bodyTemplate = `## Changelog + +{{ .Changelog }} + +--- +Automated with @goreleaser +Built with {{ .GoVersion }} +` + +func buildBody(ctx *context.Context) (bytes.Buffer, error) { + var out bytes.Buffer + bts, err := exec.Command("go", "version").CombinedOutput() + if err != nil { + return out, err + } + var template = template.Must(template.New("release").Parse(bodyTemplate)) + err = template.Execute(&out, struct { + Changelog, GoVersion string + }{ + Changelog: ctx.Changelog, + GoVersion: string(bts), + }) + return out, err +} diff --git a/pipeline/release/body_test.go b/pipeline/release/body_test.go new file mode 100644 index 000000000..2cdea8523 --- /dev/null +++ b/pipeline/release/body_test.go @@ -0,0 +1,37 @@ +package release + +import ( + "os" + "testing" + + "github.com/goreleaser/goreleaser/context" + "github.com/stretchr/testify/assert" +) + +func TestBody(t *testing.T) { + var assert = assert.New(t) + var changelog = "\nfeature1: description\nfeature2: other description" + var ctx = &context.Context{ + Changelog: changelog, + } + out, err := buildBody(ctx) + assert.NoError(err) + assert.Contains(out.String(), "## Changelog") + assert.Contains(out.String(), changelog) + assert.Contains(out.String(), "Automated with @goreleaser") + assert.Contains(out.String(), "Built with go version go1.8") +} + +func TestGoVersionFails(t *testing.T) { + var assert = assert.New(t) + var path = os.Getenv("PATH") + defer func() { + assert.NoError(os.Setenv("PATH", path)) + }() + os.Setenv("PATH", "") + var ctx = &context.Context{ + Changelog: "changelog", + } + _, err := buildBody(ctx) + assert.Error(err) +} diff --git a/pipeline/release/release.go b/pipeline/release/release.go index 09e407699..b04ae420e 100644 --- a/pipeline/release/release.go +++ b/pipeline/release/release.go @@ -30,7 +30,11 @@ func doRun(ctx *context.Context, client client.Client) error { return nil } log.Println("Creating or updating release", ctx.Git.CurrentTag, "on", ctx.Config.Release.GitHub.String()) - releaseID, err := client.CreateRelease(ctx) + body, err := buildBody(ctx) + if err != nil { + return err + } + releaseID, err := client.CreateRelease(ctx, body.String()) if err != nil { return err } diff --git a/pipeline/release/release_test.go b/pipeline/release/release_test.go index 771deeb5b..4d9adb901 100644 --- a/pipeline/release/release_test.go +++ b/pipeline/release/release_test.go @@ -148,7 +148,7 @@ func (client *DummyClient) GetInfo(ctx *context.Context) (info client.Info, err return } -func (client *DummyClient) CreateRelease(ctx *context.Context) (releaseID int, err error) { +func (client *DummyClient) CreateRelease(ctx *context.Context, body string) (releaseID int, err error) { if client.FailToCreateRelease { return 0, errors.New("release failed") }