1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

Merge pull request #76 from goreleaser/context

Really big refactory: Context
This commit is contained in:
Carlos Alexandro Becker 2017-01-14 15:36:05 -02:00 committed by GitHub
commit 0cda903340
38 changed files with 588 additions and 467 deletions

3
.gitignore vendored
View File

@ -1,4 +1,3 @@
dist
releasr
dist/
vendor
releaser

16
clients/github.go Normal file
View File

@ -0,0 +1,16 @@
package clients
import (
"context"
"github.com/google/go-github/github"
"golang.org/x/oauth2"
)
func Github(token string) *github.Client {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
tc := oauth2.NewClient(context.Background(), ts)
return github.NewClient(tc)
}

View File

View File

@ -1,45 +0,0 @@
package config
import (
"bytes"
"html/template"
)
// ArchiveConfig config used for the archive
type ArchiveConfig struct {
Format string
NameTemplate string `yaml:"name_template"`
Replacements map[string]string
}
type archiveNameData struct {
Os string
Arch string
Version string
BinaryName string
}
// ArchiveName following the given template
func (config ProjectConfig) ArchiveName(goos, goarch string) (string, error) {
var data = archiveNameData{
Os: replace(config.Archive.Replacements, goos),
Arch: replace(config.Archive.Replacements, goarch),
Version: config.Git.CurrentTag,
BinaryName: config.BinaryName,
}
var out bytes.Buffer
t, err := template.New(data.BinaryName).Parse(config.Archive.NameTemplate)
if err != nil {
return "", err
}
err = t.Execute(&out, data)
return out.String(), err
}
func replace(replacements map[string]string, original string) string {
result := replacements[original]
if result == "" {
return original
}
return result
}

View File

@ -1,27 +0,0 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNameTemplate(t *testing.T) {
assert := assert.New(t)
var config = ProjectConfig{
BinaryName: "test",
Git: GitInfo{
CurrentTag: "v1.2.3",
},
Archive: ArchiveConfig{
NameTemplate: "{{.BinaryName}}_{{.Os}}_{{.Arch}}_{{.Version}}",
Replacements: map[string]string{
"darwin": "Darwin",
"amd64": "x86_64",
},
},
}
name, err := config.ArchiveName("darwin", "amd64")
assert.NoError(err)
assert.Equal("test_Darwin_x86_64_v1.2.3", name)
}

View File

@ -1,23 +1,15 @@
package config
import (
"errors"
"io/ioutil"
"os"
"path"
"path/filepath"
"github.com/goreleaser/releaser/config/git"
yaml "gopkg.in/yaml.v1"
)
var filePatterns = []string{"LICENCE*", "LICENSE*", "README*", "CHANGELOG*"}
// Homebrew contains the brew section
type Homebrew struct {
Repo string
Folder string
Token string `yaml:"-"`
Caveats string
}
@ -29,11 +21,11 @@ type BuildConfig struct {
Ldflags string
}
// GitInfo includes tags and diffs used in some point
type GitInfo struct {
CurrentTag string
PreviousTag string
Diff string
// ArchiveConfig config used for the archive
type ArchiveConfig struct {
Format string
NameTemplate string `yaml:"name_template"`
Replacements map[string]string
}
// ProjectConfig includes all project configuration
@ -42,9 +34,7 @@ type ProjectConfig struct {
BinaryName string `yaml:"binary_name"`
Files []string
Brew Homebrew
Token string `yaml:"-"`
Build BuildConfig
Git GitInfo `yaml:"-"`
Archive ArchiveConfig
}
@ -54,123 +44,6 @@ func Load(file string) (config ProjectConfig, err error) {
if err != nil {
return config, err
}
if err := yaml.Unmarshal(data, &config); err != nil {
return config, err
}
config.fillBasicData()
if err := config.fillFiles(); err != nil {
return config, err
}
if err := config.fillGitData(); err != nil {
return config, err
}
return config, config.validate()
}
func (config *ProjectConfig) validate() (err error) {
if config.BinaryName == "" {
return errors.New("missing binary_name")
}
if config.Repo == "" {
return errors.New("missing repo")
}
return
}
func (config *ProjectConfig) fillFiles() (err error) {
if len(config.Files) != 0 {
return
}
config.Files = []string{}
for _, pattern := range filePatterns {
matches, err := globPath(pattern)
if err != nil {
return err
}
config.Files = append(config.Files, matches...)
}
return
}
func (config *ProjectConfig) fillBasicData() {
if config.Token == "" {
config.Token = os.Getenv("GITHUB_TOKEN")
}
if config.Brew.Repo != "" {
config.Brew.Token = config.Token
}
if config.Build.Main == "" {
config.Build.Main = "main.go"
}
if len(config.Build.Oses) == 0 {
config.Build.Oses = []string{"linux", "darwin"}
}
if len(config.Build.Arches) == 0 {
config.Build.Arches = []string{"amd64", "386"}
}
if config.Build.Ldflags == "" {
config.Build.Ldflags = "-s -w"
}
if config.Archive.NameTemplate == "" {
config.Archive.NameTemplate = "{{.BinaryName}}_{{.Os}}_{{.Arch}}"
}
if config.Archive.Format == "" {
config.Archive.Format = "tar.gz"
}
if len(config.Archive.Replacements) == 0 {
config.Archive.Replacements = map[string]string{
"darwin": "Darwin",
"linux": "Linux",
"freebsd": "FreeBSD",
"openbsd": "OpenBSD",
"netbsd": "NetBSD",
"windows": "Windows",
"386": "i386",
"amd64": "x86_64",
}
}
}
func (config *ProjectConfig) fillGitData() (err error) {
tag, err := git.CurrentTag()
if err != nil {
return
}
previous, err := git.PreviousTag(tag)
if err != nil {
return
}
log, err := git.Log(previous, tag)
if err != nil {
return
}
config.Git.CurrentTag = tag
config.Git.PreviousTag = previous
config.Git.Diff = log
return
}
func globPath(p string) (m []string, err error) {
var cwd string
var dirs []string
if cwd, err = os.Getwd(); err != nil {
return
}
fp := path.Join(cwd, p)
if dirs, err = filepath.Glob(fp); err != nil {
return
}
// Normalise to avoid nested dirs in tarball
for _, dir := range dirs {
_, f := filepath.Split(dir)
m = append(m, f)
}
err = yaml.Unmarshal(data, &config)
return
}

View File

@ -1,91 +0,0 @@
package config
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestFillBasicData(t *testing.T) {
assert := assert.New(t)
config := ProjectConfig{}
config.fillBasicData()
assert.Equal("main.go", config.Build.Main)
assert.Equal("tar.gz", config.Archive.Format)
assert.Contains(config.Build.Oses, "darwin")
assert.Contains(config.Build.Oses, "linux")
assert.Contains(config.Build.Arches, "386")
assert.Contains(config.Build.Arches, "amd64")
}
func TestFillFilesMissingFiles(t *testing.T) {
assert := assert.New(t)
config := ProjectConfig{}
err := config.fillFiles()
assert.NoError(err)
assert.Equal([]string{}, config.Files)
}
func TestFillFilesUSENMarkdown(t *testing.T) {
assertFiles(t, "./.test/1", []string{"LICENSE.md", "README.md"})
}
func TestFillFilesRealENMarkdown(t *testing.T) {
assertFiles(t, "./.test/2", []string{"LICENCE.md", "README.md"})
}
func TestFillFilesArbitratryENTXT(t *testing.T) {
assertFiles(t, "./.test/3", []string{"LICENCE.txt", "README.txt"})
}
func TestFillFilesArbitratryENNoSuffix(t *testing.T) {
assertFiles(t, "./.test/4", []string{"LICENCE"})
}
func TestFillFilesChangelog(t *testing.T) {
assertFiles(t, "./.test/5", []string{"CHANGELOG", "CHANGELOG.md"})
}
func TestValidadeMissingBinaryName(t *testing.T) {
assert := assert.New(t)
config := ProjectConfig{Repo: "asd/asd"}
assert.Error(config.validate())
}
func TestValidadeMissingRepo(t *testing.T) {
assert := assert.New(t)
config := ProjectConfig{BinaryName: "asd"}
assert.Error(config.validate())
}
func TestValidadeMinimalConfig(t *testing.T) {
assert := assert.New(t)
config := ProjectConfig{BinaryName: "asd", Repo: "asd/asd"}
assert.NoError(config.validate())
}
func assertFiles(t *testing.T, dir string, files []string) {
assert := assert.New(t)
cwd, _ := os.Getwd()
if err := os.Chdir(dir); err != nil {
panic(err)
}
defer func() {
if err := os.Chdir(cwd); err != nil {
panic(err)
}
}()
config := ProjectConfig{}
err := config.fillFiles()
assert.NoError(err)
assert.Equal(files, config.Files)
}

30
context/context.go Normal file
View File

@ -0,0 +1,30 @@
package context
import "github.com/goreleaser/releaser/config"
// GitInfo includes tags and diffs used in some point
type GitInfo struct {
CurrentTag string
PreviousTag string
Diff string
}
type Repo struct {
Owner, Name string
}
type Context struct {
Config *config.ProjectConfig
Token *string
Git *GitInfo
Repo *Repo
BrewRepo *Repo
Archives map[string]string
}
func New(config config.ProjectConfig) *Context {
return &Context{
Config: &config,
Archives: map[string]string{},
}
}

26
main.go
View File

@ -5,17 +5,33 @@ import (
"os"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/context"
"github.com/goreleaser/releaser/pipeline"
"github.com/goreleaser/releaser/pipeline/brew"
"github.com/goreleaser/releaser/pipeline/build"
"github.com/goreleaser/releaser/pipeline/compress"
"github.com/goreleaser/releaser/pipeline/defaults"
"github.com/goreleaser/releaser/pipeline/env"
"github.com/goreleaser/releaser/pipeline/git"
"github.com/goreleaser/releaser/pipeline/release"
"github.com/goreleaser/releaser/pipeline/repos"
"github.com/goreleaser/releaser/pipeline/valid"
"github.com/urfave/cli"
)
var version = "master"
var pipes = []pipeline.Pipe{
// load data, set defaults, etc...
defaults.Pipe{},
env.Pipe{},
git.Pipe{},
repos.Pipe{},
// validate
valid.Pipe{},
// real work
build.Pipe{},
compress.Pipe{},
release.Pipe{},
@ -40,11 +56,15 @@ func main() {
if err != nil {
return cli.NewExitError(err.Error(), 1)
}
log.Println("Releasing", config.Git.CurrentTag, "...")
context := context.New(config)
log.SetFlags(0)
for _, pipe := range pipes {
if err := pipe.Run(config); err != nil {
return cli.NewExitError(pipe.Name()+" failed: "+err.Error(), 1)
log.Println(pipe.Description())
log.SetPrefix(" -> ")
if err := pipe.Run(context); err != nil {
return cli.NewExitError(err.Error(), 1)
}
log.SetPrefix("")
}
log.Println("Done!")
return

View File

@ -2,17 +2,15 @@ package brew
import (
"bytes"
"context"
"log"
"path/filepath"
"strings"
"text/template"
"github.com/google/go-github/github"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/clients"
"github.com/goreleaser/releaser/context"
"github.com/goreleaser/releaser/sha256sum"
"github.com/goreleaser/releaser/split"
"golang.org/x/oauth2"
)
const formulae = `class {{ .Name }} < Formula
@ -43,25 +41,20 @@ type templateData struct {
type Pipe struct{}
// Name of the pipe
func (Pipe) Name() string {
return "Homebrew"
func (Pipe) Description() string {
return "Creating homebrew formulae..."
}
// Run the pipe
func (Pipe) Run(config config.ProjectConfig) error {
if config.Brew.Repo == "" {
func (Pipe) Run(ctx *context.Context) error {
if ctx.Config.Brew.Repo == "" {
return nil
}
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: config.Token},
)
tc := oauth2.NewClient(context.Background(), ts)
client := github.NewClient(tc)
client := clients.Github(*ctx.Token)
path := filepath.Join(ctx.Config.Brew.Folder, ctx.Config.BinaryName+".rb")
owner, repo := split.OnSlash(config.Brew.Repo)
path := filepath.Join(config.Brew.Folder, config.BinaryName+".rb")
log.Println("Updating", path, "on", config.Brew.Repo, "...")
out, err := buildFormulae(config, client)
log.Println("Updating", path, "on", ctx.Config.Brew.Repo, "...")
out, err := buildFormulae(ctx, client)
if err != nil {
return err
}
@ -72,9 +65,13 @@ func (Pipe) Run(config config.ProjectConfig) error {
Email: github.String("bot@goreleaser"),
},
Content: out.Bytes(),
Message: github.String(config.BinaryName + " version " + config.Git.CurrentTag),
Message: github.String(
ctx.Config.BinaryName + " version " + ctx.Git.CurrentTag,
),
}
owner := ctx.BrewRepo.Owner
repo := ctx.BrewRepo.Name
file, _, res, err := client.Repositories.GetContents(
owner, repo, path, &github.RepositoryContentGetOptions{},
)
@ -87,8 +84,8 @@ func (Pipe) Run(config config.ProjectConfig) error {
return err
}
func buildFormulae(config config.ProjectConfig, client *github.Client) (bytes.Buffer, error) {
data, err := dataFor(config, client)
func buildFormulae(ctx *context.Context, client *github.Client) (bytes.Buffer, error) {
data, err := dataFor(ctx, client)
if err != nil {
return bytes.Buffer{}, err
}
@ -105,19 +102,15 @@ func doBuildFormulae(data templateData) (bytes.Buffer, error) {
return out, err
}
func dataFor(config config.ProjectConfig, client *github.Client) (result templateData, err error) {
func dataFor(ctx *context.Context, client *github.Client) (result templateData, err error) {
var homepage string
var description string
owner, repo := split.OnSlash(config.Repo)
rep, _, err := client.Repositories.Get(owner, repo)
rep, _, err := client.Repositories.Get(ctx.Repo.Owner, ctx.Repo.Name)
if err != nil {
return
}
file, err := config.ArchiveName("darwin", "amd64")
if err != nil {
return
}
sum, err := sha256sum.For("dist/" + file + "." + config.Archive.Format)
file := ctx.Archives["darwinamd64"]
sum, err := sha256sum.For("dist/" + file + "." + ctx.Config.Archive.Format)
if err != nil {
return
}
@ -132,15 +125,15 @@ func dataFor(config config.ProjectConfig, client *github.Client) (result templat
description = *rep.Description
}
return templateData{
Name: formulaNameFor(config.BinaryName),
Name: formulaNameFor(ctx.Config.BinaryName),
Desc: description,
Homepage: homepage,
Repo: config.Repo,
Tag: config.Git.CurrentTag,
BinaryName: config.BinaryName,
Caveats: config.Brew.Caveats,
Repo: ctx.Config.Repo,
Tag: ctx.Git.CurrentTag,
BinaryName: ctx.Config.BinaryName,
Caveats: ctx.Config.Brew.Caveats,
File: file,
Format: config.Archive.Format,
Format: ctx.Config.Archive.Format,
SHA256: sum,
}, err
}

View File

@ -7,7 +7,7 @@ import (
"os"
"os/exec"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/context"
"golang.org/x/sync/errgroup"
)
@ -15,44 +15,45 @@ import (
type Pipe struct{}
// Name of the pipe
func (Pipe) Name() string {
return "Build"
func (Pipe) Description() string {
return "Building..."
}
// Run the pipe
func (Pipe) Run(config config.ProjectConfig) error {
func (Pipe) Run(ctx *context.Context) error {
var g errgroup.Group
for _, system := range config.Build.Oses {
for _, arch := range config.Build.Arches {
system := system
arch := arch
for _, goos := range ctx.Config.Build.Oses {
for _, goarch := range ctx.Config.Build.Arches {
goos := goos
goarch := goarch
name, err := nameFor(ctx, goos, goarch)
if err != nil {
return err
}
ctx.Archives[goos+goarch] = name
g.Go(func() error {
return build(system, arch, config)
return build(name, goos, goarch, ctx)
})
}
}
return g.Wait()
}
func build(system, arch string, config config.ProjectConfig) error {
name, err := config.ArchiveName(system, arch)
if err != nil {
return err
}
ldflags := config.Build.Ldflags + " -X main.version=" + config.Git.CurrentTag
output := "dist/" + name + "/" + config.BinaryName
func build(name, goos, goarch string, ctx *context.Context) error {
ldflags := ctx.Config.Build.Ldflags + " -X main.version=" + ctx.Git.CurrentTag
output := "dist/" + name + "/" + ctx.Config.BinaryName + extFor(goos)
log.Println("Building", output, "...")
cmd := exec.Command(
"go",
"build",
"-ldflags="+ldflags,
"-o", output,
config.Build.Main,
ctx.Config.Build.Main,
)
cmd.Env = append(
cmd.Env,
"GOOS="+system,
"GOARCH="+arch,
"GOOS="+goos,
"GOARCH="+goarch,
"GOROOT="+os.Getenv("GOROOT"),
"GOPATH="+os.Getenv("GOPATH"),
)

46
pipeline/build/name.go Normal file
View File

@ -0,0 +1,46 @@
package build
import (
"bytes"
"text/template"
"github.com/goreleaser/releaser/context"
)
type nameData struct {
Os string
Arch string
Version string
BinaryName string
}
func nameFor(ctx *context.Context, goos, goarch string) (string, error) {
var data = nameData{
Os: replace(ctx.Config.Archive.Replacements, goos),
Arch: replace(ctx.Config.Archive.Replacements, goarch),
Version: ctx.Git.CurrentTag,
BinaryName: ctx.Config.BinaryName,
}
var out bytes.Buffer
t, err := template.New(data.BinaryName).Parse(ctx.Config.Archive.NameTemplate)
if err != nil {
return "", err
}
err = t.Execute(&out, data)
return out.String(), err
}
func replace(replacements map[string]string, original string) string {
result := replacements[original]
if result == "" {
return original
}
return result
}
func extFor(goos string) string {
if goos == "windows" {
return ".exe"
}
return ""
}

View File

@ -0,0 +1,42 @@
package build
import (
"testing"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/context"
"github.com/stretchr/testify/assert"
)
func TestExtWindows(t *testing.T) {
assert.Equal(t, extFor("windows"), ".exe")
}
func TestExtOthers(t *testing.T) {
assert.Empty(t, extFor("linux"))
}
func TestNameFor(t *testing.T) {
assert := assert.New(t)
var config = &config.ProjectConfig{
BinaryName: "test",
Archive: config.ArchiveConfig{
NameTemplate: "{{.BinaryName}}_{{.Os}}_{{.Arch}}_{{.Version}}",
Replacements: map[string]string{
"darwin": "Darwin",
"amd64": "x86_64",
},
},
}
var ctx = &context.Context{
Config: config,
Git: &context.GitInfo{
CurrentTag: "v1.2.3",
},
}
name, err := nameFor(ctx, "darwin", "amd64")
assert.NoError(err)
assert.Equal("test_Darwin_x86_64_v1.2.3", name)
}

View File

@ -1,10 +1,12 @@
package compress
import (
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/context"
"github.com/goreleaser/releaser/pipeline/compress/tar"
"github.com/goreleaser/releaser/pipeline/compress/zip"
"golang.org/x/sync/errgroup"
@ -14,21 +16,18 @@ import (
type Pipe struct{}
// Name of the pipe
func (Pipe) Name() string {
return "Compress"
func (Pipe) Description() string {
return "Creating archives..."
}
// Run the pipe
func (Pipe) Run(config config.ProjectConfig) error {
func (Pipe) Run(ctx *context.Context) error {
var g errgroup.Group
for _, system := range config.Build.Oses {
for _, arch := range config.Build.Arches {
system := system
arch := arch
g.Go(func() error {
return create(system, arch, config)
})
}
for _, archive := range ctx.Archives {
archive := archive
g.Go(func() error {
return create(archive, ctx)
})
}
return g.Wait()
}
@ -38,25 +37,31 @@ type Archive interface {
Add(name, path string) error
}
func create(system, arch string, config config.ProjectConfig) error {
name, err := config.ArchiveName(system, arch)
if err != nil {
return err
}
file, err := os.Create("dist/" + name + "." + config.Archive.Format)
func create(name string, ctx *context.Context) error {
folder := filepath.Join("dist", name)
file, err := os.Create(folder + "." + ctx.Config.Archive.Format)
log.Println("Creating", file.Name(), "...")
if err != nil {
return err
}
defer func() { _ = file.Close() }()
var archive = archiveFor(file, config.Archive.Format)
var archive = archiveFor(file, ctx.Config.Archive.Format)
defer func() { _ = archive.Close() }()
for _, f := range config.Files {
if err := archive.Add(f, f); err != nil {
for _, f := range ctx.Config.Files {
if err = archive.Add(f, f); err != nil {
return err
}
}
return archive.Add(config.BinaryName+extFor(system), "dist/"+name+"/"+config.BinaryName)
files, err := ioutil.ReadDir(folder)
if err != nil {
return err
}
for _, f := range files {
if err := archive.Add(f.Name(), filepath.Join(folder, f.Name())); err != nil {
return err
}
}
return nil
}
func archiveFor(file *os.File, format string) Archive {
@ -65,10 +70,3 @@ func archiveFor(file *os.File, format string) Archive {
}
return tar.New(file)
}
func extFor(system string) string {
if system == "windows" {
return ".exe"
}
return ""
}

View File

@ -1,15 +0,0 @@
package compress
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestExtWindows(t *testing.T) {
assert.Equal(t, extFor("windows"), ".exe")
}
func TestExtOthers(t *testing.T) {
assert.Empty(t, extFor("linux"))
}

View File

@ -0,0 +1,83 @@
package defaults
import (
"io/ioutil"
"strings"
"github.com/goreleaser/releaser/context"
)
var defaultFiles = []string{"licence", "license", "readme", "changelog"}
// Pipe for brew deployment
type Pipe struct{}
// Name of the pipe
func (Pipe) Description() string {
return "Setting defaults..."
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
if ctx.Config.Build.Main == "" {
ctx.Config.Build.Main = "main.go"
}
if len(ctx.Config.Build.Oses) == 0 {
ctx.Config.Build.Oses = []string{"linux", "darwin"}
}
if len(ctx.Config.Build.Arches) == 0 {
ctx.Config.Build.Arches = []string{"amd64", "386"}
}
if ctx.Config.Build.Ldflags == "" {
ctx.Config.Build.Ldflags = "-s -w"
}
if ctx.Config.Archive.NameTemplate == "" {
ctx.Config.Archive.NameTemplate = "{{.BinaryName}}_{{.Os}}_{{.Arch}}"
}
if ctx.Config.Archive.Format == "" {
ctx.Config.Archive.Format = "tar.gz"
}
if len(ctx.Config.Archive.Replacements) == 0 {
ctx.Config.Archive.Replacements = map[string]string{
"darwin": "Darwin",
"linux": "Linux",
"freebsd": "FreeBSD",
"openbsd": "OpenBSD",
"netbsd": "NetBSD",
"windows": "Windows",
"386": "i386",
"amd64": "x86_64",
}
}
if len(ctx.Config.Files) != 0 {
return
}
files, err := findFiles()
if err != nil {
return
}
ctx.Config.Files = files
return
}
func findFiles() (files []string, err error) {
all, err := ioutil.ReadDir(".")
if err != nil {
return
}
for _, file := range all {
if accept(file.Name()) {
files = append(files, file.Name())
}
}
return
}
func accept(file string) bool {
for _, accepted := range defaultFiles {
if strings.HasPrefix(strings.ToLower(file), accepted) {
return true
}
}
return false
}

View File

@ -0,0 +1,69 @@
package defaults
import (
"testing"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/context"
"github.com/stretchr/testify/assert"
)
func TestFillBasicData(t *testing.T) {
assert := assert.New(t)
var config = &config.ProjectConfig{}
var ctx = &context.Context{
Config: config,
}
assert.NoError(Pipe{}.Run(ctx))
assert.Equal("main.go", config.Build.Main)
assert.Equal("tar.gz", config.Archive.Format)
assert.Contains(config.Build.Oses, "darwin")
assert.Contains(config.Build.Oses, "linux")
assert.Contains(config.Build.Arches, "386")
assert.Contains(config.Build.Arches, "amd64")
assert.NotEmpty(
config.Archive.Replacements,
config.Archive.NameTemplate,
config.Build.Ldflags,
config.Files,
)
}
func TestFilesFilled(t *testing.T) {
assert := assert.New(t)
var config = &config.ProjectConfig{
Files: []string{
"README.md",
},
}
var ctx = &context.Context{
Config: config,
}
assert.NoError(Pipe{}.Run(ctx))
assert.Len(config.Files, 1)
}
func TestAcceptFiles(t *testing.T) {
assert := assert.New(t)
var files = []string{
"LICENSE.md",
"LIceNSE.txt",
"LICENSE",
"LICENCE.txt",
"LICEncE",
"README",
"READme.md",
"CHANGELOG.txt",
"ChanGELOG.md",
}
for _, file := range files {
assert.True(accept(file))
}
}

28
pipeline/env/env.go vendored Normal file
View File

@ -0,0 +1,28 @@
package env
import (
"errors"
"os"
"github.com/goreleaser/releaser/context"
)
var ErrMissingToken = errors.New("Missing GITHUB_TOKEN")
// Pipe for env
type Pipe struct{}
// Name of the pipe
func (Pipe) Description() string {
return "Loading data from environment variables..."
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
token := os.Getenv("GITHUB_TOKEN")
if token == "" {
return ErrMissingToken
}
ctx.Token = &token
return
}

34
pipeline/git/git.go Normal file
View File

@ -0,0 +1,34 @@
package git
import "github.com/goreleaser/releaser/context"
// Pipe for brew deployment
type Pipe struct{}
// Name of the pipe
func (Pipe) Description() string {
return "Gathering Git data..."
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
tag, err := currentTag()
if err != nil {
return
}
previous, err := previousTag(tag)
if err != nil {
return
}
log, err := log(previous, tag)
if err != nil {
return
}
ctx.Git = &context.GitInfo{
CurrentTag: tag,
PreviousTag: previous,
Diff: log,
}
return
}

View File

@ -2,8 +2,7 @@ package git
import "os/exec"
// Log between two tags
func Log(previous, current string) (str string, err error) {
func log(previous, current string) (str string, err error) {
cmd := exec.Command(
"git",
"log",

View File

@ -8,14 +8,14 @@ import (
func TestLog(t *testing.T) {
assert := assert.New(t)
log, err := Log("v0.1.9", "v0.2.0")
log, err := log("v0.1.9", "v0.2.0")
assert.NoError(err)
assert.NotEmpty(log)
}
func TestLogInvalidRef(t *testing.T) {
assert := assert.New(t)
log, err := Log("wtfff", "nope")
log, err := log("wtfff", "nope")
assert.Error(err)
assert.Empty(log)
}

View File

@ -6,13 +6,11 @@ import (
"strings"
)
// CurrentTag tag being built
func CurrentTag() (tag string, err error) {
func currentTag() (tag string, err error) {
return getTag("")
}
// PreviousTag previous tag of the base tag
func PreviousTag(base string) (tag string, err error) {
func previousTag(base string) (tag string, err error) {
return getTag(base + "^")
}

View File

@ -8,21 +8,21 @@ import (
func TestCurrentTag(t *testing.T) {
assert := assert.New(t)
tag, err := CurrentTag()
tag, err := currentTag()
assert.NoError(err)
assert.NotEmpty(tag)
}
func TestPreviousTag(t *testing.T) {
assert := assert.New(t)
tag, err := PreviousTag("v0.2.0")
tag, err := previousTag("v0.2.0")
assert.NoError(err)
assert.NotEmpty(tag)
}
func TestInvalidRef(t *testing.T) {
assert := assert.New(t)
tag, err := PreviousTag("this-should-not-exist")
tag, err := previousTag("this-should-not-exist")
assert.Error(err)
assert.Empty(tag)
}

View File

@ -1,12 +1,12 @@
package pipeline
import "github.com/goreleaser/releaser/config"
import "github.com/goreleaser/releaser/context"
// Pipe interface
type Pipe interface {
// Name of the pipe
Name() string
Description() string
// Run the pipe
Run(config config.ProjectConfig) error
Run(ctx *context.Context) error
}

View File

@ -1,15 +1,13 @@
package release
import (
"context"
"log"
"os"
"os/exec"
"github.com/google/go-github/github"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/split"
"golang.org/x/oauth2"
"github.com/goreleaser/releaser/clients"
"github.com/goreleaser/releaser/context"
"golang.org/x/sync/errgroup"
)
@ -17,49 +15,44 @@ import (
type Pipe struct{}
// Name of the pipe
func (Pipe) Name() string {
return "GithubRelease"
func (Pipe) Description() string {
return "Releasing to GitHub..."
}
// Run the pipe
func (Pipe) Run(config config.ProjectConfig) error {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: config.Token},
)
tc := oauth2.NewClient(context.Background(), ts)
client := github.NewClient(tc)
func (Pipe) Run(ctx *context.Context) error {
client := clients.Github(*ctx.Token)
r, err := getOrCreateRelease(client, config)
r, err := getOrCreateRelease(client, ctx)
if err != nil {
return err
}
var g errgroup.Group
for _, system := range config.Build.Oses {
for _, arch := range config.Build.Arches {
system := system
arch := arch
g.Go(func() error {
return upload(client, *r.ID, system, arch, config)
})
}
for _, archive := range ctx.Archives {
archive := archive
g.Go(func() error {
return upload(client, *r.ID, archive, ctx)
})
}
return g.Wait()
}
func getOrCreateRelease(client *github.Client, config config.ProjectConfig) (*github.RepositoryRelease, error) {
owner, repo := split.OnSlash(config.Repo)
func getOrCreateRelease(client *github.Client, ctx *context.Context) (*github.RepositoryRelease, error) {
owner := ctx.Repo.Owner
repo := ctx.Repo.Name
data := &github.RepositoryRelease{
Name: github.String(config.Git.CurrentTag),
TagName: github.String(config.Git.CurrentTag),
Body: github.String(description(config.Git.Diff)),
Name: github.String(ctx.Git.CurrentTag),
TagName: github.String(ctx.Git.CurrentTag),
Body: github.String(description(ctx.Git.Diff)),
}
r, res, err := client.Repositories.GetReleaseByTag(owner, repo, config.Git.CurrentTag)
if err != nil && res.StatusCode == 404 {
log.Println("Creating release", config.Git.CurrentTag, "on", config.Repo, "...")
r, _, err := client.Repositories.GetReleaseByTag(owner, repo, ctx.Git.CurrentTag)
if err != nil {
log.Println("Creating release", ctx.Git.CurrentTag, "on", ctx.Config.Repo, "...")
r, _, err = client.Repositories.CreateRelease(owner, repo, data)
return r, err
}
log.Println("Updating existing release", config.Git.CurrentTag, "on", config.Repo, "...")
log.Println("Updating existing release", ctx.Git.CurrentTag, "on", ctx.Config.Repo, "...")
r, _, err = client.Repositories.EditRelease(owner, repo, *r.ID, data)
return r, err
}
@ -74,26 +67,19 @@ func description(diff string) string {
return result + "\nBuilt with " + string(bts)
}
func upload(client *github.Client, releaseID int, system, arch string, config config.ProjectConfig) error {
owner, repo := split.OnSlash(config.Repo)
name, err := config.ArchiveName(system, arch)
func upload(client *github.Client, releaseID int, archive string, ctx *context.Context) error {
archive = archive + "." + ctx.Config.Archive.Format
file, err := os.Open("dist/" + archive)
if err != nil {
return err
}
name = name + "." + config.Archive.Format
file, err := os.Open("dist/" + name)
if err != nil {
return err
}
defer func() {
_ = file.Close()
}()
defer func() { _ = file.Close() }()
log.Println("Uploading", file.Name(), "...")
_, _, err = client.Repositories.UploadReleaseAsset(
owner,
repo,
ctx.Repo.Owner,
ctx.Repo.Name,
releaseID,
&github.UploadOptions{Name: name},
&github.UploadOptions{Name: archive},
file,
)
return err

35
pipeline/repos/repos.go Normal file
View File

@ -0,0 +1,35 @@
package repos
import (
"strings"
"github.com/goreleaser/releaser/context"
)
// Pipe for brew deployment
type Pipe struct{}
// Name of the pipe
func (Pipe) Description() string {
return "Filling repositories data..."
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
owner, name := split(ctx.Config.Repo)
ctx.Repo = &context.Repo{
Owner: owner,
Name: name,
}
owner, name = split(ctx.Config.Brew.Repo)
ctx.BrewRepo = &context.Repo{
Owner: owner,
Name: name,
}
return
}
func split(pair string) (string, string) {
parts := strings.Split(pair, "/")
return parts[0], parts[1]
}

View File

@ -1,4 +1,4 @@
package split
package repos
import (
"testing"
@ -8,7 +8,7 @@ import (
func TestSplit(t *testing.T) {
assert := assert.New(t)
a, b := OnSlash("a/b")
a, b := split("a/b")
assert.Equal("a", a)
assert.Equal("b", b)
}

26
pipeline/valid/valid.go Normal file
View File

@ -0,0 +1,26 @@
package valid
import (
"errors"
"github.com/goreleaser/releaser/context"
)
// Pipe for brew deployment
type Pipe struct{}
// Name of the pipe
func (Pipe) Description() string {
return "Validating configuration..."
}
// Run the pipe
func (Pipe) Run(ctx *context.Context) (err error) {
if ctx.Config.BinaryName == "" {
return errors.New("missing binary_name")
}
if ctx.Config.Repo == "" {
return errors.New("missing repo")
}
return
}

View File

@ -0,0 +1,32 @@
package valid
import (
"testing"
"github.com/goreleaser/releaser/config"
"github.com/goreleaser/releaser/context"
"github.com/stretchr/testify/assert"
)
func runPipe(repo, bin string) error {
var config = &config.ProjectConfig{
Repo: repo,
BinaryName: bin,
}
var ctx = &context.Context{
Config: config,
}
return Pipe{}.Run(ctx)
}
func TestValidadeMissingBinaryName(t *testing.T) {
assert.Error(t, runPipe("a/b", ""))
}
func TestValidadeMissingRepo(t *testing.T) {
assert.Error(t, runPipe("", "a"))
}
func TestValidadeMinimalConfig(t *testing.T) {
assert.NoError(t, runPipe("a/b", "a"))
}

View File

@ -1,9 +0,0 @@
package split
import "strings"
// OnSlash split a string on / and return the first 2 parts
func OnSlash(pair string) (string, string) {
parts := strings.Split(pair, "/")
return parts[0], parts[1]
}