diff --git a/.gitignore b/.gitignore index 3f1e75f10..d8e6f606b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -dist -releasr +dist/ vendor releaser diff --git a/clients/github.go b/clients/github.go new file mode 100644 index 000000000..45807ad3f --- /dev/null +++ b/clients/github.go @@ -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) +} diff --git a/config/.test/1/LICENSE.md b/config/.test/1/LICENSE.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/1/README.md b/config/.test/1/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/2/LICENCE.md b/config/.test/2/LICENCE.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/2/README.md b/config/.test/2/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/3/LICENCE.txt b/config/.test/3/LICENCE.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/3/README.txt b/config/.test/3/README.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/4/LICENCE b/config/.test/4/LICENCE deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/5/CHANGELOG b/config/.test/5/CHANGELOG deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/.test/5/CHANGELOG.md b/config/.test/5/CHANGELOG.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/archive_config.go b/config/archive_config.go deleted file mode 100644 index c9fc6b761..000000000 --- a/config/archive_config.go +++ /dev/null @@ -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 -} diff --git a/config/archive_config_test.go b/config/archive_config_test.go deleted file mode 100644 index 9fb929651..000000000 --- a/config/archive_config_test.go +++ /dev/null @@ -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) -} diff --git a/config/config.go b/config/config.go index da31b4eb2..e123a083f 100644 --- a/config/config.go +++ b/config/config.go @@ -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 } diff --git a/config/config_test.go b/config/config_test.go deleted file mode 100644 index 0cdad4a76..000000000 --- a/config/config_test.go +++ /dev/null @@ -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) -} diff --git a/context/context.go b/context/context.go new file mode 100644 index 000000000..415f929dd --- /dev/null +++ b/context/context.go @@ -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{}, + } +} diff --git a/main.go b/main.go index e51ac7fb1..47a191fc9 100644 --- a/main.go +++ b/main.go @@ -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 diff --git a/pipeline/brew/brew.go b/pipeline/brew/brew.go index 69d329779..048fbf69e 100644 --- a/pipeline/brew/brew.go +++ b/pipeline/brew/brew.go @@ -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 } diff --git a/pipeline/build/build.go b/pipeline/build/build.go index 8140f782d..6c82a4f58 100644 --- a/pipeline/build/build.go +++ b/pipeline/build/build.go @@ -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"), ) diff --git a/pipeline/build/name.go b/pipeline/build/name.go new file mode 100644 index 000000000..049b869e4 --- /dev/null +++ b/pipeline/build/name.go @@ -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 "" +} diff --git a/pipeline/build/name_test.go b/pipeline/build/name_test.go new file mode 100644 index 000000000..62cdc644d --- /dev/null +++ b/pipeline/build/name_test.go @@ -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) +} diff --git a/pipeline/compress/compress.go b/pipeline/compress/compress.go index 0b4c9f880..3f0a2217c 100644 --- a/pipeline/compress/compress.go +++ b/pipeline/compress/compress.go @@ -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 "" -} diff --git a/pipeline/compress/compress_test.go b/pipeline/compress/compress_test.go deleted file mode 100644 index 5b2c7c910..000000000 --- a/pipeline/compress/compress_test.go +++ /dev/null @@ -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")) -} diff --git a/pipeline/defaults/defaults.go b/pipeline/defaults/defaults.go new file mode 100644 index 000000000..adcb1fe14 --- /dev/null +++ b/pipeline/defaults/defaults.go @@ -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 +} diff --git a/pipeline/defaults/defaults_test.go b/pipeline/defaults/defaults_test.go new file mode 100644 index 000000000..7df77f4a1 --- /dev/null +++ b/pipeline/defaults/defaults_test.go @@ -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)) + } +} diff --git a/pipeline/env/env.go b/pipeline/env/env.go new file mode 100644 index 000000000..b35b9ab28 --- /dev/null +++ b/pipeline/env/env.go @@ -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 +} diff --git a/pipeline/git/git.go b/pipeline/git/git.go new file mode 100644 index 000000000..ed2e5f39c --- /dev/null +++ b/pipeline/git/git.go @@ -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 +} diff --git a/config/git/log.go b/pipeline/git/log.go similarity index 73% rename from config/git/log.go rename to pipeline/git/log.go index 0b4d73285..b4d4feeed 100644 --- a/config/git/log.go +++ b/pipeline/git/log.go @@ -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", diff --git a/config/git/log_test.go b/pipeline/git/log_test.go similarity index 79% rename from config/git/log_test.go rename to pipeline/git/log_test.go index c309fd867..52abcac5a 100644 --- a/config/git/log_test.go +++ b/pipeline/git/log_test.go @@ -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) } diff --git a/config/git/tag.go b/pipeline/git/tag.go similarity index 72% rename from config/git/tag.go rename to pipeline/git/tag.go index 4c26246b6..d856c959d 100644 --- a/config/git/tag.go +++ b/pipeline/git/tag.go @@ -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 + "^") } diff --git a/config/git/tag_test.go b/pipeline/git/tag_test.go similarity index 77% rename from config/git/tag_test.go rename to pipeline/git/tag_test.go index 77ba71d14..c1d4b12d2 100644 --- a/config/git/tag_test.go +++ b/pipeline/git/tag_test.go @@ -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) } diff --git a/pipeline/pipe.go b/pipeline/pipe.go index c6f7a0058..2395469d6 100644 --- a/pipeline/pipe.go +++ b/pipeline/pipe.go @@ -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 } diff --git a/pipeline/release/release.go b/pipeline/release/release.go index 98cf6b4dc..66ddb9152 100644 --- a/pipeline/release/release.go +++ b/pipeline/release/release.go @@ -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 diff --git a/pipeline/repos/repos.go b/pipeline/repos/repos.go new file mode 100644 index 000000000..17f82c2f7 --- /dev/null +++ b/pipeline/repos/repos.go @@ -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] +} diff --git a/split/split_test.go b/pipeline/repos/repos_test.go similarity index 81% rename from split/split_test.go rename to pipeline/repos/repos_test.go index 8541d068a..6c21c4706 100644 --- a/split/split_test.go +++ b/pipeline/repos/repos_test.go @@ -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) } diff --git a/pipeline/valid/valid.go b/pipeline/valid/valid.go new file mode 100644 index 000000000..710e51a13 --- /dev/null +++ b/pipeline/valid/valid.go @@ -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 +} diff --git a/pipeline/valid/valid_test.go b/pipeline/valid/valid_test.go new file mode 100644 index 000000000..35a6bb001 --- /dev/null +++ b/pipeline/valid/valid_test.go @@ -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")) +} diff --git a/split/split.go b/split/split.go deleted file mode 100644 index c5338e4f9..000000000 --- a/split/split.go +++ /dev/null @@ -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] -}