1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-29 21:47:01 +02:00

Merge pull request #154 from goreleaser/client

client interface
This commit is contained in:
Carlos Alexandro Becker 2017-03-26 15:59:09 -03:00 committed by GitHub
commit e70f76fbc5
7 changed files with 341 additions and 137 deletions

34
clients/client.go Normal file
View File

@ -0,0 +1,34 @@
package clients
import (
"bytes"
"os"
"os/exec"
"github.com/goreleaser/goreleaser/context"
)
// Info of the repository
type Info struct {
Description string
Homepage string
URL string
}
// Client interface
type Client interface {
GetInfo(ctx *context.Context) (info Info, err error)
CreateRelease(ctx *context.Context) (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)
}

15
clients/client_test.go Normal file
View File

@ -0,0 +1,15 @@
package clients
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.")
}

View File

@ -1,15 +1,139 @@
package clients
import (
"bytes"
"os"
"github.com/google/go-github/github"
"github.com/goreleaser/goreleaser/context"
"golang.org/x/oauth2"
)
// GitHub client for the given token
func GitHub(ctx *context.Context) *github.Client {
type githubClient struct {
client *github.Client
}
// NewGitHubClient impl
func NewGitHubClient(ctx *context.Context) Client {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: ctx.Token},
)
return github.NewClient(oauth2.NewClient(ctx, ts))
return &githubClient{
client: github.NewClient(oauth2.NewClient(ctx, ts)),
}
}
func (c *githubClient) CreateFile(
ctx *context.Context,
content bytes.Buffer,
path string,
) (err error) {
options := &github.RepositoryContentFileOptions{
Committer: &github.CommitAuthor{
Name: github.String("goreleaserbot"),
Email: github.String("bot@goreleaser"),
},
Content: content.Bytes(),
Message: github.String(
ctx.Config.Build.Binary + " version " + ctx.Git.CurrentTag,
),
}
file, _, res, err := c.client.Repositories.GetContents(
ctx,
ctx.Config.Brew.GitHub.Owner,
ctx.Config.Brew.GitHub.Name,
path,
&github.RepositoryContentGetOptions{},
)
if err != nil && res.StatusCode == 404 {
_, _, err = c.client.Repositories.CreateFile(
ctx,
ctx.Config.Brew.GitHub.Owner,
ctx.Config.Brew.GitHub.Name,
path,
options,
)
return
}
options.SHA = file.SHA
_, _, err = c.client.Repositories.UpdateFile(
ctx,
ctx.Config.Brew.GitHub.Owner,
ctx.Config.Brew.GitHub.Name,
path,
options,
)
return
}
func (c *githubClient) GetInfo(ctx *context.Context) (info Info, err error) {
rep, _, err := c.client.Repositories.Get(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
)
if err != nil {
return
}
if rep.Homepage != nil {
info.Homepage = *rep.Homepage
}
if rep.HTMLURL != nil {
info.URL = *rep.HTMLURL
}
if rep.Description != nil {
info.Description = *rep.Description
}
return
}
func (c *githubClient) CreateRelease(ctx *context.Context) (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)),
}
r, _, err := c.client.Repositories.GetReleaseByTag(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
ctx.Git.CurrentTag,
)
if err != nil {
r, _, err = c.client.Repositories.CreateRelease(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
data,
)
return *r.ID, err
}
r, _, err = c.client.Repositories.EditRelease(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
*r.ID,
data,
)
return *r.ID, err
}
func (c *githubClient) Upload(
ctx *context.Context,
releaseID int,
name string,
file *os.File,
) (err error) {
_, _, err = c.client.Repositories.UploadReleaseAsset(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
releaseID,
&github.UploadOptions{
Name: name,
},
file,
)
return err
}

View File

@ -8,7 +8,6 @@ import (
"strings"
"text/template"
"github.com/google/go-github/github"
"github.com/goreleaser/goreleaser/clients"
"github.com/goreleaser/goreleaser/config"
"github.com/goreleaser/goreleaser/context"
@ -89,6 +88,11 @@ func (Pipe) Description() string {
// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
client := clients.NewGitHubClient(ctx)
return doRun(ctx, client)
}
func doRun(ctx *context.Context, client clients.Client) error {
// TODO: remove this block in next release cycle
if ctx.Config.Brew.Repo != "" {
log.Println("The `brew.repo` syntax is deprecated and will soon be removed. Please check the README for more info.")
@ -101,57 +105,16 @@ func (Pipe) Run(ctx *context.Context) error {
if ctx.Config.Brew.GitHub.Name == "" {
return nil
}
client := clients.GitHub(ctx)
path := filepath.Join(
ctx.Config.Brew.Folder, ctx.Config.Build.Binary+".rb",
)
path := filepath.Join(ctx.Config.Brew.Folder, ctx.Config.Build.Binary+".rb")
log.Println("Pushing", path, "to", ctx.Config.Brew.GitHub.String())
out, err := buildFormula(ctx, client)
content, err := buildFormula(ctx, client)
if err != nil {
return err
}
options := &github.RepositoryContentFileOptions{
Committer: &github.CommitAuthor{
Name: github.String("goreleaserbot"),
Email: github.String("bot@goreleaser"),
},
Content: out.Bytes(),
Message: github.String(
ctx.Config.Build.Binary + " version " + ctx.Git.CurrentTag,
),
}
file, _, res, err := client.Repositories.GetContents(
ctx,
ctx.Config.Brew.GitHub.Owner,
ctx.Config.Brew.GitHub.Name,
path,
&github.RepositoryContentGetOptions{},
)
if err != nil && res.StatusCode == 404 {
_, _, err = client.Repositories.CreateFile(
ctx,
ctx.Config.Brew.GitHub.Owner,
ctx.Config.Brew.GitHub.Name,
path,
options,
)
return err
}
options.SHA = file.SHA
_, _, err = client.Repositories.UpdateFile(
ctx,
ctx.Config.Brew.GitHub.Owner,
ctx.Config.Brew.GitHub.Name,
path,
options,
)
return err
return client.CreateFile(ctx, content, path)
}
func buildFormula(ctx *context.Context, client *github.Client) (bytes.Buffer, error) {
func buildFormula(ctx *context.Context, client clients.Client) (bytes.Buffer, error) {
data, err := dataFor(ctx, client)
if err != nil {
return bytes.Buffer{}, err
@ -169,19 +132,7 @@ func doBuildFormula(data templateData) (bytes.Buffer, error) {
return out, err
}
func dataFor(
ctx *context.Context, client *github.Client,
) (result templateData, err error) {
var homepage string
var description string
rep, _, err := client.Repositories.Get(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
)
if err != nil {
return
}
func dataFor(ctx *context.Context, client clients.Client) (result templateData, err error) {
file := ctx.Archives["darwinamd64"]
if file == "" {
return result, ErrNoDarwin64Build
@ -195,15 +146,9 @@ func dataFor(
if err != nil {
return
}
if rep.Homepage != nil && *rep.Homepage != "" {
homepage = *rep.Homepage
} else {
homepage = *rep.HTMLURL
}
if rep.Description == nil {
description = "TODO"
} else {
description = *rep.Description
homepage, description, err := getInfo(ctx, client)
if err != nil {
return
}
return templateData{
Name: formulaNameFor(ctx.Config.Build.Binary),
@ -224,6 +169,27 @@ func dataFor(
}, err
}
func getInfo(
ctx *context.Context,
client clients.Client,
) (homepage string, description string, err error) {
info, err := client.GetInfo(ctx)
if err != nil {
return
}
if info.Homepage == "" {
homepage = info.URL
} else {
homepage = info.Homepage
}
if info.Description == "" {
description = "TODO"
} else {
description = info.Description
}
return
}
func formulaNameFor(name string) string {
name = strings.Replace(name, "-", " ", -1)
name = strings.Replace(name, "_", " ", -1)

View File

@ -1,9 +1,15 @@
package brew
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/goreleaser/goreleaser/clients"
"github.com/goreleaser/goreleaser/config"
"github.com/goreleaser/goreleaser/context"
"github.com/stretchr/testify/assert"
)
@ -80,3 +86,52 @@ func TestFormulaeSimple(t *testing.T) {
assert.NotContains(formulae, "depends_on")
assert.NotContains(formulae, "def plist;")
}
func TestRunPipe(t *testing.T) {
assert := assert.New(t)
folder, err := ioutil.TempDir("", "gorelasertest")
assert.NoError(err)
_, err = os.Create(filepath.Join(folder, "bin.tar.gz"))
assert.NoError(err)
var ctx = &context.Context{
Config: config.Project{
Dist: folder,
Archive: config.Archive{
Format: "tar.gz",
},
Brew: config.Homebrew{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
Archives: map[string]string{
"darwinamd64": "bin",
},
}
client := &DummyClient{}
assert.NoError(doRun(ctx, client))
assert.True(client.CreatedFile)
}
type DummyClient struct {
CreatedFile bool
}
func (client *DummyClient) GetInfo(ctx *context.Context) (info clients.Info, err error) {
return
}
func (client *DummyClient) CreateRelease(ctx *context.Context) (releaseID int, err error) {
return
}
func (client *DummyClient) CreateFile(ctx *context.Context, content bytes.Buffer, path string) (err error) {
client.CreatedFile = true
return
}
func (client *DummyClient) Upload(ctx *context.Context, releaseID int, name string, file *os.File) (err error) {
return
}

View File

@ -3,10 +3,8 @@ package release
import (
"log"
"os"
"os/exec"
"path/filepath"
"github.com/google/go-github/github"
"github.com/goreleaser/goreleaser/clients"
"github.com/goreleaser/goreleaser/context"
"golang.org/x/sync/errgroup"
@ -22,9 +20,13 @@ func (Pipe) Description() string {
// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
client := clients.GitHub(ctx)
client := clients.NewGitHubClient(ctx)
return doRun(ctx, client)
}
r, err := getOrCreateRelease(client, ctx)
func doRun(ctx *context.Context, client clients.Client) error {
log.Println("Creating or updating release", ctx.Git.CurrentTag, "on", ctx.Config.Release.GitHub.String())
releaseID, err := client.CreateRelease(ctx)
if err != nil {
return err
}
@ -32,62 +34,19 @@ func (Pipe) Run(ctx *context.Context) error {
for _, archive := range ctx.Archives {
archive := archive
g.Go(func() error {
return upload(ctx, client, *r.ID, archive, ctx.Config.Archive.Format)
return upload(ctx, client, releaseID, archive, ctx.Config.Archive.Format)
})
for _, format := range ctx.Config.FPM.Formats {
format := format
g.Go(func() error {
return upload(ctx, client, *r.ID, archive, format)
return upload(ctx, client, releaseID, archive, format)
})
}
}
return g.Wait()
}
func getOrCreateRelease(client *github.Client, ctx *context.Context) (*github.RepositoryRelease, error) {
data := &github.RepositoryRelease{
Name: github.String(ctx.Git.CurrentTag),
TagName: github.String(ctx.Git.CurrentTag),
Body: github.String(description(ctx.Git.Diff)),
}
r, _, err := client.Repositories.GetReleaseByTag(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
ctx.Git.CurrentTag,
)
if err != nil {
log.Println("Creating release", ctx.Git.CurrentTag, "on", ctx.Config.Release.GitHub.String())
r, _, err = client.Repositories.CreateRelease(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
data,
)
return r, err
}
log.Println("Updating existing release", ctx.Git.CurrentTag, "on", ctx.Config.Release.GitHub.String())
r, _, err = client.Repositories.EditRelease(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
*r.ID,
data,
)
return r, err
}
func description(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)
}
func upload(ctx *context.Context, client *github.Client, releaseID int, archive, format string) error {
func upload(ctx *context.Context, client clients.Client, releaseID int, archive, format string) error {
archive = archive + "." + format
var path = filepath.Join(ctx.Config.Dist, archive)
// In case the file doesn't exist, we just ignore it.
@ -106,13 +65,5 @@ func upload(ctx *context.Context, client *github.Client, releaseID int, archive,
}
defer func() { _ = file.Close() }()
log.Println("Uploading", file.Name())
_, _, err = client.Repositories.UploadReleaseAsset(
ctx,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
releaseID,
&github.UploadOptions{Name: archive},
file,
)
return err
return client.Upload(ctx, releaseID, archive, file)
}

View File

@ -1,9 +1,15 @@
package release
import (
"fmt"
"bytes"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/goreleaser/goreleaser/clients"
"github.com/goreleaser/goreleaser/config"
"github.com/goreleaser/goreleaser/context"
"github.com/stretchr/testify/assert"
)
@ -11,11 +17,64 @@ func TestPipeDescription(t *testing.T) {
assert.NotEmpty(t, Pipe{}.Description())
}
func TestDescription(t *testing.T) {
func TestRunPipe(t *testing.T) {
assert := assert.New(t)
desc := description("0abf342 some message")
assert.Contains(desc, "0abf342 some message")
assert.Contains(desc, "Automated with @goreleaser")
assert.Contains(desc, "go version go1.")
fmt.Println(desc)
folder, err := ioutil.TempDir("", "gorelasertest")
assert.NoError(err)
_, err = os.Create(filepath.Join(folder, "bin.tar.gz"))
assert.NoError(err)
_, err = os.Create(filepath.Join(folder, "bin.deb"))
assert.NoError(err)
var ctx = &context.Context{
Git: context.GitInfo{
CurrentTag: "v1.0.0",
},
Config: config.Project{
Dist: folder,
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
FPM: config.FPM{
Formats: []string{
"deb",
},
},
},
Archives: map[string]string{
"darwinamd64": "bin",
},
}
client := &DummyClient{}
assert.NoError(doRun(ctx, client))
assert.True(client.CreatedRelease)
assert.True(client.UploadedFile)
}
type DummyClient struct {
CreatedRelease bool
UploadedFile bool
}
func (client *DummyClient) GetInfo(ctx *context.Context) (info clients.Info, err error) {
return
}
func (client *DummyClient) CreateRelease(ctx *context.Context) (releaseID int, err error) {
client.CreatedRelease = true
return
}
func (client *DummyClient) CreateFile(ctx *context.Context, content bytes.Buffer, path string) (err error) {
return
}
func (client *DummyClient) Upload(ctx *context.Context, releaseID int, name string, file *os.File) (err error) {
client.UploadedFile = true
return
}