1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-10-30 23:58:09 +02:00

feat: multiple brew / linuxbrew (#1043)

* feat: multiple brew / linuxbrew

* feat: multiple brew / linuxbrew

* test: added missing tests

* docs: brews

* docs: deprecate brew

* test: fix tests

* fix: fmt

* test: fix tests
This commit is contained in:
Carlos Alexandro Becker
2019-06-10 10:35:19 -03:00
committed by GitHub
parent 60b9584361
commit 1ef9906e04
19 changed files with 452 additions and 307 deletions

View File

@@ -193,6 +193,18 @@ func ByType(t Type) Filter {
}
}
// ByFormats filters artifacts by a `Format` extra field.
func ByFormats(formats ...string) Filter {
var filters = make([]Filter, 0, len(formats))
for _, format := range formats {
format := format
filters = append(filters, func(a Artifact) bool {
return a.ExtraOr("Format", "") == format
})
}
return Or(filters...)
}
// ByIDs filter artifacts by an `ID` extra field.
func ByIDs(ids ...string) Filter {
var filters = make([]Filter, 0, len(ids))

View File

@@ -232,3 +232,40 @@ func TestByIDs(t *testing.T) {
require.Len(t, artifacts.Filter(ByIDs("foo")).items, 2)
require.Len(t, artifacts.Filter(ByIDs("foo", "bar")).items, 3)
}
func TestByFormats(t *testing.T) {
var data = []Artifact{
{
Name: "foo",
Extra: map[string]interface{}{
"Format": "zip",
},
},
{
Name: "bar",
Extra: map[string]interface{}{
"Format": "tar.gz",
},
},
{
Name: "foobar",
Extra: map[string]interface{}{
"Format": "zip",
},
},
{
Name: "bin",
Extra: map[string]interface{}{
"Format": "binary",
},
},
}
var artifacts = New()
for _, a := range data {
artifacts.Add(a)
}
require.Len(t, artifacts.Filter(ByFormats("binary")).items, 1)
require.Len(t, artifacts.Filter(ByFormats("zip")).items, 2)
require.Len(t, artifacts.Filter(ByFormats("zip", "tar.gz")).items, 3)
}

View File

@@ -169,6 +169,7 @@ func create(ctx *context.Context, archive config.Archive, binaries []artifact.Ar
Extra: map[string]interface{}{
"Builds": binaries,
"ID": archive.ID,
"Format": archive.Format,
},
})
return nil
@@ -204,6 +205,7 @@ func skip(ctx *context.Context, archive config.Archive, binaries []artifact.Arti
Extra: map[string]interface{}{
"Builds": []artifact.Artifact{binary},
"ID": archive.ID,
"Format": archive.Format,
},
})
}

View File

@@ -561,10 +561,12 @@ func TestBinaryOverride(t *testing.T) {
var archives = ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableArchive))
darwin := archives.Filter(artifact.ByGoos("darwin")).List()[0]
require.Equal(tt, "foobar_0.0.1_darwin_amd64."+format, darwin.Name)
require.Equal(tt, format, darwin.ExtraOr("Format", ""))
archives = ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableBinary))
windows := archives.Filter(artifact.ByGoos("windows")).List()[0]
require.Equal(tt, "foobar_0.0.1_windows_amd64.exe", windows.Name)
require.Equal(tt, format, windows.ExtraOr("Format", ""))
})
}
}

View File

@@ -7,23 +7,28 @@ import (
"io/ioutil"
"path"
"path/filepath"
"reflect"
"strings"
"text/template"
"github.com/apex/log"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/client"
"github.com/goreleaser/goreleaser/internal/deprecate"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/internal/semerrgroup"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
)
// ErrNoDarwin64Build when there is no build for darwin_amd64
var ErrNoDarwin64Build = errors.New("brew tap requires one darwin amd64 build")
// ErrNoArchivesFound happens when 0 archives are found
var ErrNoArchivesFound = errors.New("brew tap: no archives found matching criteria")
// ErrTooManyDarwin64Builds when there are too many builds for darwin_amd64
var ErrTooManyDarwin64Builds = errors.New("brew tap requires at most one darwin amd64 build")
// ErrMultipleArchivesSameOS happens when the config yields multiple archives
// for linux or windows.
// TODO: improve this confusing error message
var ErrMultipleArchivesSameOS = errors.New("brew tap: one tap can handle only 1 linux and 1 macos archive")
// Pipe for brew deployment
type Pipe struct{}
@@ -38,34 +43,53 @@ func (Pipe) Publish(ctx *context.Context) error {
if err != nil {
return err
}
return doRun(ctx, client)
var g = semerrgroup.New(ctx.Parallelism)
for _, brew := range ctx.Config.Brews {
brew := brew
g.Go(func() error {
return doRun(ctx, brew, client)
})
}
return g.Wait()
}
// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
if ctx.Config.Brew.Install == "" {
var installs []string
for _, build := range ctx.Config.Builds {
if !isBrewBuild(build) {
continue
}
installs = append(
installs,
fmt.Sprintf(`bin.install "%s"`, build.Binary),
)
if len(ctx.Config.Brews) == 0 {
ctx.Config.Brews = append(ctx.Config.Brews, ctx.Config.Brew)
if !reflect.DeepEqual(ctx.Config.Brew, config.Homebrew{}) {
deprecate.Notice("brew")
}
}
for i := range ctx.Config.Brews {
var brew = &ctx.Config.Brews[i]
if brew.Install == "" {
// TODO: maybe replace this with a simplear also optimistic
// approach of just doing `bin.install "project_name"`?
var installs []string
for _, build := range ctx.Config.Builds {
if !isBrewBuild(build) {
continue
}
installs = append(
installs,
fmt.Sprintf(`bin.install "%s"`, build.Binary),
)
}
brew.Install = strings.Join(installs, "\n")
log.Warnf("optimistically guessing `brew[%d].installs`, double check", i)
}
if brew.CommitAuthor.Name == "" {
brew.CommitAuthor.Name = "goreleaserbot"
}
if brew.CommitAuthor.Email == "" {
brew.CommitAuthor.Email = "goreleaser@carlosbecker.com"
}
if brew.Name == "" {
brew.Name = ctx.Config.ProjectName
}
ctx.Config.Brew.Install = strings.Join(installs, "\n")
}
if ctx.Config.Brew.CommitAuthor.Name == "" {
ctx.Config.Brew.CommitAuthor.Name = "goreleaserbot"
}
if ctx.Config.Brew.CommitAuthor.Email == "" {
ctx.Config.Brew.CommitAuthor.Email = "goreleaser@carlosbecker.com"
}
if ctx.Config.Brew.Name == "" {
ctx.Config.Brew.Name = ctx.Config.ProjectName
}
return nil
}
@@ -87,42 +111,41 @@ func contains(ss []string, s string) bool {
return false
}
func doRun(ctx *context.Context, client client.Client) error {
if ctx.Config.Brew.GitHub.Name == "" {
func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) error {
if brew.GitHub.Name == "" {
return pipe.Skip("brew section is not configured")
}
if getFormat(ctx) == "binary" {
return pipe.Skip("archive format is binary")
}
var archives = ctx.Artifacts.Filter(
artifact.And(
var filters = []artifact.Filter{
artifact.Or(
artifact.ByGoos("darwin"),
artifact.ByGoarch("amd64"),
artifact.ByGoarm(""),
artifact.ByType(artifact.UploadableArchive),
artifact.ByGoos("linux"),
),
).List()
if len(archives) == 0 {
return ErrNoDarwin64Build
artifact.ByFormats("zip", "tar.gz"),
artifact.ByGoarch("amd64"),
artifact.ByType(artifact.UploadableArchive),
}
if len(archives) > 1 {
return ErrTooManyDarwin64Builds
if len(brew.IDs) > 0 {
filters = append(filters, artifact.ByIDs(brew.IDs...))
}
content, err := buildFormula(ctx, archives[0])
var archives = ctx.Artifacts.Filter(artifact.And(filters...)).List()
if len(archives) == 0 {
return ErrNoArchivesFound
}
content, err := buildFormula(ctx, brew, archives)
if err != nil {
return err
}
var filename = ctx.Config.Brew.Name + ".rb"
var filename = brew.Name + ".rb"
var path = filepath.Join(ctx.Config.Dist, filename)
log.WithField("formula", path).Info("writing")
if err := ioutil.WriteFile(path, content.Bytes(), 0644); err != nil {
return err
}
if strings.TrimSpace(ctx.Config.Brew.SkipUpload) == "true" {
if strings.TrimSpace(brew.SkipUpload) == "true" {
return pipe.Skip("brew.skip_upload is set")
}
if ctx.SkipPublish {
@@ -131,34 +154,25 @@ func doRun(ctx *context.Context, client client.Client) error {
if ctx.Config.Release.Draft {
return pipe.Skip("release is marked as draft")
}
if strings.TrimSpace(ctx.Config.Brew.SkipUpload) == "auto" && ctx.Semver.Prerelease != "" {
if strings.TrimSpace(brew.SkipUpload) == "auto" && ctx.Semver.Prerelease != "" {
return pipe.Skip("prerelease detected with 'auto' upload, skipping homebrew publish")
}
var gpath = ghFormulaPath(ctx.Config.Brew.Folder, filename)
var gpath = ghFormulaPath(brew.Folder, filename)
log.WithField("formula", gpath).
WithField("repo", ctx.Config.Brew.GitHub.String()).
WithField("repo", brew.GitHub.String()).
Info("pushing")
var msg = fmt.Sprintf("Brew formula update for %s version %s", ctx.Config.ProjectName, ctx.Git.CurrentTag)
return client.CreateFile(ctx, ctx.Config.Brew.CommitAuthor, ctx.Config.Brew.GitHub, content, gpath, msg)
return client.CreateFile(ctx, brew.CommitAuthor, brew.GitHub, content, gpath, msg)
}
func ghFormulaPath(folder, filename string) string {
return path.Join(folder, filename)
}
func getFormat(ctx *context.Context) string {
for _, override := range ctx.Config.Archive.FormatOverrides {
if strings.HasPrefix(override.Goos, "darwin") {
return override.Format
}
}
return ctx.Config.Archive.Format
}
func buildFormula(ctx *context.Context, artifact artifact.Artifact) (bytes.Buffer, error) {
data, err := dataFor(ctx, artifact)
func buildFormula(ctx *context.Context, brew config.Homebrew, artifacts []artifact.Artifact) (bytes.Buffer, error) {
data, err := dataFor(ctx, brew, artifacts)
if err != nil {
return bytes.Buffer{}, err
}
@@ -174,32 +188,13 @@ func doBuildFormula(data templateData) (out bytes.Buffer, err error) {
return
}
func dataFor(ctx *context.Context, artifact artifact.Artifact) (result templateData, err error) {
sum, err := artifact.Checksum("sha256")
if err != nil {
return
}
var cfg = ctx.Config.Brew
if ctx.Config.Brew.URLTemplate == "" {
ctx.Config.Brew.URLTemplate = fmt.Sprintf("%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
ctx.Config.GitHubURLs.Download,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name)
}
url, err := tmpl.New(ctx).WithArtifact(artifact, map[string]string{}).Apply(ctx.Config.Brew.URLTemplate)
if err != nil {
return
}
return templateData{
Name: formulaNameFor(ctx.Config.Brew.Name),
DownloadURL: url,
func dataFor(ctx *context.Context, cfg config.Homebrew, artifacts []artifact.Artifact) (templateData, error) {
var result = templateData{
Name: formulaNameFor(cfg.Name),
Desc: cfg.Description,
Homepage: cfg.Homepage,
Version: ctx.Version,
Caveats: split(cfg.Caveats),
SHA256: sum,
Dependencies: cfg.Dependencies,
Conflicts: cfg.Conflicts,
Plist: cfg.Plist,
@@ -208,7 +203,44 @@ func dataFor(ctx *context.Context, artifact artifact.Artifact) (result templateD
DownloadStrategy: cfg.DownloadStrategy,
CustomRequire: cfg.CustomRequire,
CustomBlock: split(cfg.CustomBlock),
}, nil
}
for _, artifact := range artifacts {
sum, err := artifact.Checksum("sha256")
if err != nil {
return result, err
}
if cfg.URLTemplate == "" {
cfg.URLTemplate = fmt.Sprintf(
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
ctx.Config.GitHubURLs.Download,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
)
}
url, err := tmpl.New(ctx).WithArtifact(artifact, map[string]string{}).Apply(cfg.URLTemplate)
if err != nil {
return result, err
}
var down = downloadable{
DownloadURL: url,
SHA256: sum,
}
if artifact.Goos == "darwin" {
if result.MacOS.DownloadURL != "" {
return result, ErrMultipleArchivesSameOS
}
result.MacOS = down
} else if artifact.Goos == "linux" {
if result.Linux.DownloadURL != "" {
return result, ErrMultipleArchivesSameOS
}
result.Linux = down
}
}
return result, nil
}
func split(s string) []string {

View File

@@ -35,13 +35,19 @@ func TestSimpleName(t *testing.T) {
}
var defaultTemplateData = templateData{
Desc: "Some desc",
Homepage: "https://google.com",
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Darwin_x86_64.tar.gz",
Name: "Test",
Version: "0.1.3",
Caveats: []string{},
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c68",
Desc: "Some desc",
Homepage: "https://google.com",
MacOS: downloadable{
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Darwin_x86_64.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c68",
},
Linux: downloadable{
DownloadURL: "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz",
SHA256: "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67",
},
Name: "Test",
Version: "0.1.3",
Caveats: []string{},
}
func assertDefaultTemplateData(t *testing.T, formulae string) {
@@ -101,23 +107,14 @@ func TestRunPipe(t *testing.T) {
ctx.Config.GitHubURLs.Download = "http://github.example.org"
},
"custom_download_strategy": func(ctx *context.Context) {
ctx.Config.Brew.DownloadStrategy = "GitHubPrivateRepositoryReleaseDownloadStrategy"
ctx.Config.Brews[0].DownloadStrategy = "GitHubPrivateRepositoryReleaseDownloadStrategy"
},
"custom_require": func(ctx *context.Context) {
ctx.Config.Brew.DownloadStrategy = "CustomDownloadStrategy"
ctx.Config.Brew.CustomRequire = "custom_download_strategy"
},
"binary_overridden": func(ctx *context.Context) {
ctx.Config.Archive.Format = "binary"
ctx.Config.Archive.FormatOverrides = []config.FormatOverride{
{
Goos: "darwin",
Format: "zip",
},
}
ctx.Config.Brews[0].DownloadStrategy = "CustomDownloadStrategy"
ctx.Config.Brews[0].CustomRequire = "custom_download_strategy"
},
"custom_block": func(ctx *context.Context) {
ctx.Config.Brew.CustomBlock = `head "https://github.com/caarlos0/test.git"`
ctx.Config.Brews[0].CustomBlock = `head "https://github.com/caarlos0/test.git"`
},
} {
t.Run(name, func(t *testing.T) {
@@ -135,41 +132,57 @@ func TestRunPipe(t *testing.T) {
GitHubURLs: config.GitHubURLs{
Download: "https://github.com",
},
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
Brew: config.Homebrew{
Name: name,
GitHub: config.Repo{
Owner: "test",
Name: "test",
Brews: []config.Homebrew{
{
Name: name,
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
IDs: []string{
"foo",
},
Description: "A run pipe test formula",
Homepage: "https://github.com/goreleaser",
Caveats: "don't do this",
Test: "system \"true\"\nsystem \"#{bin}/foo -h\"",
Plist: `<xml>whatever</xml>`,
Dependencies: []string{"zsh", "bash"},
Conflicts: []string{"gtk+", "qt"},
Install: `bin.install "foo"`,
},
Description: "A run pipe test formula",
Homepage: "https://github.com/goreleaser",
Caveats: "don't do this",
Test: "system \"true\"\nsystem \"#{bin}/foo -h\"",
Plist: `<xml>whatever</xml>`,
Dependencies: []string{"zsh", "bash"},
Conflicts: []string{"gtk+", "qt"},
Install: `bin.install "foo"`,
},
},
}
fn(ctx)
var format = getFormat(ctx)
var path = filepath.Join(folder, "bin."+format)
ctx.Artifacts.Add(artifact.Artifact{
Name: "bin." + format,
Name: "bar_bin.tar.gz",
Path: "doesnt matter",
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "bar",
"Format": "tar.gz",
},
})
var path = filepath.Join(folder, "bin.tar.gz")
ctx.Artifacts.Add(artifact.Artifact{
Name: "bin.tar.gz",
Path: path,
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "foo",
"Format": "tar.gz",
},
})
_, err = os.Create(path)
@@ -177,7 +190,7 @@ func TestRunPipe(t *testing.T) {
client := &DummyClient{}
var distFile = filepath.Join(folder, name+".rb")
assert.NoError(t, doRun(ctx, client))
assert.NoError(t, doRun(ctx, ctx.Config.Brews[0], client))
assert.True(t, client.CreatedFile)
var golden = fmt.Sprintf("testdata/%s.rb.golden", name)
if *update {
@@ -197,52 +210,62 @@ func TestRunPipe(t *testing.T) {
func TestRunPipeNoDarwin64Build(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{
Archive: config.Archive{
Format: "tar.gz",
},
Brew: config.Homebrew{
GitHub: config.Repo{
Owner: "test",
Name: "test",
Brews: []config.Homebrew{
{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
},
}
client := &DummyClient{}
assert.Equal(t, ErrNoDarwin64Build, doRun(ctx, client))
assert.Equal(t, ErrNoArchivesFound, doRun(ctx, ctx.Config.Brews[0], client))
assert.False(t, client.CreatedFile)
}
func TestRunPipeMultipleDarwin64Build(t *testing.T) {
var ctx = context.New(
config.Project{
Archive: config.Archive{
Format: "tar.gz",
},
Brew: config.Homebrew{
GitHub: config.Repo{
Owner: "test",
Name: "test",
Brews: []config.Homebrew{
{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
},
)
f, err := ioutil.TempFile("", "")
assert.NoError(t, err)
defer f.Close()
ctx.Artifacts.Add(artifact.Artifact{
Name: "bin1",
Path: "doesnt mather",
Path: f.Name(),
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "foo",
"Format": "tar.gz",
},
})
ctx.Artifacts.Add(artifact.Artifact{
Name: "bin2",
Path: "doesnt mather",
Path: f.Name(),
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "bar",
"Format": "tar.gz",
},
})
client := &DummyClient{}
assert.Equal(t, ErrTooManyDarwin64Builds, doRun(ctx, client))
assert.Equal(t, ErrMultipleArchivesSameOS, doRun(ctx, ctx.Config.Brews[0], client))
assert.False(t, client.CreatedFile)
}
@@ -251,20 +274,19 @@ func TestRunPipeBrewNotSetup(t *testing.T) {
Config: config.Project{},
}
client := &DummyClient{}
testlib.AssertSkipped(t, doRun(ctx, client))
testlib.AssertSkipped(t, doRun(ctx, config.Homebrew{}, client))
assert.False(t, client.CreatedFile)
}
func TestRunPipeBinaryRelease(t *testing.T) {
var ctx = context.New(
config.Project{
Archive: config.Archive{
Format: "binary",
},
Brew: config.Homebrew{
GitHub: config.Repo{
Owner: "test",
Name: "test",
Brews: []config.Homebrew{
{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
},
@@ -277,7 +299,7 @@ func TestRunPipeBinaryRelease(t *testing.T) {
Type: artifact.Binary,
})
client := &DummyClient{}
testlib.AssertSkipped(t, doRun(ctx, client))
assert.Equal(t, ErrNoArchivesFound, doRun(ctx, ctx.Config.Brews[0], client))
assert.False(t, client.CreatedFile)
}
@@ -288,10 +310,12 @@ func TestRunPipeNoUpload(t *testing.T) {
Dist: folder,
ProjectName: "foo",
Release: config.Release{},
Brew: config.Homebrew{
GitHub: config.Repo{
Owner: "test",
Name: "test",
Brews: []config.Homebrew{
{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
})
@@ -305,34 +329,38 @@ func TestRunPipeNoUpload(t *testing.T) {
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "foo",
"Format": "tar.gz",
},
})
client := &DummyClient{}
var assertNoPublish = func(t *testing.T) {
testlib.AssertSkipped(t, doRun(ctx, client))
testlib.AssertSkipped(t, doRun(ctx, ctx.Config.Brews[0], client))
assert.False(t, client.CreatedFile)
}
t.Run("skip upload", func(tt *testing.T) {
ctx.Config.Release.Draft = false
ctx.Config.Brew.SkipUpload = "true"
ctx.Config.Brews[0].SkipUpload = "true"
ctx.SkipPublish = false
assertNoPublish(tt)
})
t.Run("skip publish", func(tt *testing.T) {
ctx.Config.Release.Draft = false
ctx.Config.Brew.SkipUpload = "false"
ctx.Config.Brews[0].SkipUpload = "false"
ctx.SkipPublish = true
assertNoPublish(tt)
})
t.Run("draft release", func(tt *testing.T) {
ctx.Config.Release.Draft = true
ctx.Config.Brew.SkipUpload = "false"
ctx.Config.Brews[0].SkipUpload = "false"
ctx.SkipPublish = false
assertNoPublish(tt)
})
t.Run("skip prerelease publish", func(tt *testing.T) {
ctx.Config.Release.Draft = false
ctx.Config.Brew.SkipUpload = "auto"
ctx.Config.Brews[0].SkipUpload = "auto"
ctx.SkipPublish = false
ctx.Semver = context.Semver{
Major: 1,
@@ -344,19 +372,6 @@ func TestRunPipeNoUpload(t *testing.T) {
})
}
func TestRunPipeFormatBinary(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{
Archive: config.Archive{
Format: "binary",
},
},
}
client := &DummyClient{}
testlib.AssertSkipped(t, doRun(ctx, client))
assert.False(t, client.CreatedFile)
}
func TestDefault(t *testing.T) {
_, back := testlib.Mktmp(t)
defer back()
@@ -364,6 +379,7 @@ func TestDefault(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{
ProjectName: "myproject",
Brews: []config.Homebrew{},
Builds: []config.Build{
{
Binary: "foo",
@@ -387,10 +403,10 @@ func TestDefault(t *testing.T) {
},
}
assert.NoError(t, Pipe{}.Default(ctx))
assert.Equal(t, ctx.Config.ProjectName, ctx.Config.Brew.Name)
assert.NotEmpty(t, ctx.Config.Brew.CommitAuthor.Name)
assert.NotEmpty(t, ctx.Config.Brew.CommitAuthor.Email)
assert.Equal(t, `bin.install "foo"`, ctx.Config.Brew.Install)
assert.Equal(t, ctx.Config.ProjectName, ctx.Config.Brews[0].Name)
assert.NotEmpty(t, ctx.Config.Brews[0].CommitAuthor.Name)
assert.NotEmpty(t, ctx.Config.Brews[0].CommitAuthor.Email)
assert.Equal(t, `bin.install "foo"`, ctx.Config.Brews[0].Install)
}
func TestGHFolder(t *testing.T) {

View File

@@ -4,10 +4,8 @@ type templateData struct {
Name string
Desc string
Homepage string
DownloadURL string
Version string
Caveats []string
SHA256 string
Plist string
DownloadStrategy string
Install []string
@@ -16,6 +14,13 @@ type templateData struct {
Tests []string
CustomRequire string
CustomBlock []string
MacOS downloadable
Linux downloadable
}
type downloadable struct {
DownloadURL string
SHA256 string
}
const formulaTemplate = `# This file was generated by GoReleaser. DO NOT EDIT.
@@ -25,10 +30,21 @@ require_relative "{{ .CustomRequire }}"
class {{ .Name }} < Formula
desc "{{ .Desc }}"
homepage "{{ .Homepage }}"
url "{{ .DownloadURL }}"
{{- if .DownloadStrategy }}, :using => {{ .DownloadStrategy }}{{- end }}
version "{{ .Version }}"
sha256 "{{ .SHA256 }}"
if OS.mac?
{{- if .MacOS.DownloadURL }}
url "{{ .MacOS.DownloadURL }}"
sha256 "{{ .MacOS.SHA256 }}"
{{- end }}
elsif OS.linux?
{{- if .Linux.DownloadURL }}
url "{{ .Linux.DownloadURL }}"
sha256 "{{ .Linux.SHA256 }}"
{{- end }}
end
{{- if .DownloadStrategy }}, :using => {{ .DownloadStrategy }}{{- end }}
{{- with .CustomBlock }}
{{ range $index, $element := . }}

View File

@@ -2,9 +2,12 @@
class BinaryOverridden < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "https://github.com/test/test/releases/download/v1.0.1/bin.zip"
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if OS.mac?
url "https://github.com/test/test/releases/download/v1.0.1/bin.todo"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end
depends_on "zsh"
depends_on "bash"

View File

@@ -1,36 +0,0 @@
class BuildFromSource < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "https://github.com/test/test/archive/v1.0.1.tar.gz"
head "https://github.com/test/test.git"
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
depends_on "zsh"
depends_on "bash"
depends_on "go" => :build
conflicts_with "gtk+"
conflicts_with "qt"
def install
bin.install "foo"
end
def caveats; <<~EOS
don't do this
EOS
end
plist_options :startup => false
def plist; <<~EOS
<xml>whatever</xml>
EOS
end
test do
system "true"
system "#{bin}/foo -h"
end
end

View File

@@ -2,9 +2,13 @@
class CustomBlock < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz"
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if OS.mac?
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end
head "https://github.com/caarlos0/test.git"

View File

@@ -2,9 +2,13 @@
class CustomDownloadStrategy < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if OS.mac?
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end, :using => GitHubPrivateRepositoryReleaseDownloadStrategy
depends_on "zsh"
depends_on "bash"

View File

@@ -3,9 +3,13 @@ require_relative "custom_download_strategy"
class CustomRequire < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz", :using => CustomDownloadStrategy
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if OS.mac?
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end, :using => CustomDownloadStrategy
depends_on "zsh"
depends_on "bash"

View File

@@ -2,9 +2,13 @@
class Default < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz"
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if OS.mac?
url "https://github.com/test/test/releases/download/v1.0.1/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end
depends_on "zsh"
depends_on "bash"

View File

@@ -2,9 +2,13 @@
class GithubEnterpriseUrl < Formula
desc "A run pipe test formula"
homepage "https://github.com/goreleaser"
url "http://github.example.org/test/test/releases/download/v1.0.1/bin.tar.gz"
version "1.0.1"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if OS.mac?
url "http://github.example.org/test/test/releases/download/v1.0.1/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end
depends_on "zsh"
depends_on "bash"

View File

@@ -2,9 +2,15 @@
class Test < Formula
desc "Some desc"
homepage "https://google.com"
url "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Darwin_x86_64.tar.gz"
version "0.1.3"
sha256 "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c68"
if OS.mac?
url "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Darwin_x86_64.tar.gz"
sha256 "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c68"
elsif OS.linux?
url "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Linux_x86_64.tar.gz"
sha256 "1633f61598ab0791e213135923624eb342196b3494909c91899bcd0560f84c67"
end
devel do
url "https://github.com/caarlos0/test/releases/download/v0.1.3/test_Darwin_x86_64.tar.gz"

View File

@@ -35,7 +35,7 @@ func TestFillBasicData(t *testing.T) {
assert.Contains(t, ctx.Config.Builds[0].Goarch, "386")
assert.Contains(t, ctx.Config.Builds[0].Goarch, "amd64")
assert.Equal(t, "tar.gz", ctx.Config.Archives[0].Format)
assert.Contains(t, ctx.Config.Brew.Install, "bin.install \"goreleaser\"")
assert.Contains(t, ctx.Config.Brews[0].Install, "bin.install \"goreleaser\"")
assert.Empty(t, ctx.Config.Dockers)
assert.Equal(t, "https://github.com", ctx.Config.GitHubURLs.Download)
assert.NotEmpty(t, ctx.Config.Archives[0].NameTemplate)
@@ -86,7 +86,7 @@ func TestFillPartial(t *testing.T) {
}
assert.NoError(t, Pipe{}.Run(ctx))
assert.Len(t, ctx.Config.Archive.Files, 1)
assert.Equal(t, `bin.install "testreleaser"`, ctx.Config.Brew.Install)
assert.Equal(t, `bin.install "testreleaser"`, ctx.Config.Brews[0].Install)
assert.NotEmpty(t, ctx.Config.Dockers[0].Binaries)
assert.NotEmpty(t, ctx.Config.Dockers[0].Goos)
assert.NotEmpty(t, ctx.Config.Dockers[0].Goarch)

View File

@@ -50,10 +50,10 @@ type Homebrew struct {
Homepage string `yaml:",omitempty"`
SkipUpload string `yaml:"skip_upload,omitempty"`
DownloadStrategy string `yaml:"download_strategy,omitempty"`
SourceTarball string `yaml:"-"`
URLTemplate string `yaml:"url_template,omitempty"`
CustomRequire string `yaml:"custom_require,omitempty"`
CustomBlock string `yaml:"custom_block,omitempty"`
IDs []string `yaml:"ids,omitempty"`
}
// Scoop contains the scoop.sh section
@@ -326,7 +326,8 @@ type Project struct {
ProjectName string `yaml:"project_name,omitempty"`
Env []string `yaml:",omitempty"`
Release Release `yaml:",omitempty"`
Brew Homebrew `yaml:",omitempty"`
Brew Homebrew `yaml:",omitempty"` // TODO: remove this
Brews []Homebrew `yaml:",omitempty"`
Scoop Scoop `yaml:",omitempty"`
Builds []Build `yaml:",omitempty"`
Archive Archive `yaml:",omitempty"` // TODO: remove this

View File

@@ -33,6 +33,27 @@ to this:
-->
### brew
> since 2019-06-09
Brew was deprecated in favor of its plural form.
Change this:
```yaml
brew:
# etc
```
to this:
```yaml
brews:
-
# etc
```
### s3
> since 2019-06-09

View File

@@ -17,92 +17,99 @@ for more details.
```yml
# .goreleaser.yml
brew:
# Name template of the recipe
# Default to project name
name: myproject
brews:
-
# Name template of the recipe
# Default to project name
name: myproject
# Repository to push the tap to.
github:
owner: user
name: homebrew-tap
# IDs of the archives to use.
# Defaults to all.
ids:
- foo
- bar
# Template for the url.
# Default is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
# Repository to push the tap to.
github:
owner: user
name: homebrew-tap
# Allows you to set a custom download strategy.
# Default is empty.
download_strategy: GitHubPrivateRepositoryReleaseDownloadStrategy
# Template for the url.
# Default is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
# Allows you to add a custom require_relative at the top of the formula template
# Default is empty
custom_require: custom_download_strategy
# Allows you to set a custom download strategy.
# Default is empty.
download_strategy: GitHubPrivateRepositoryReleaseDownloadStrategy
# Git author used to commit to the repository.
# Defaults are shown.
commit_author:
name: goreleaserbot
email: goreleaser@carlosbecker.com
# Allows you to add a custom require_relative at the top of the formula template
# Default is empty
custom_require: custom_download_strategy
# Folder inside the repository to put the formula.
# Default is the root folder.
folder: Formula
# Git author used to commit to the repository.
# Defaults are shown.
commit_author:
name: goreleaserbot
email: goreleaser@carlosbecker.com
# Caveats for the user of your binary.
# Default is empty.
caveats: "How to use this binary"
# Folder inside the repository to put the formula.
# Default is the root folder.
folder: Formula
# Your app's homepage.
# Default is empty.
homepage: "https://example.com/"
# Caveats for the user of your binary.
# Default is empty.
caveats: "How to use this binary"
# Your app's description.
# Default is empty.
description: "Software to create fast and easy drum rolls."
# Your app's homepage.
# Default is empty.
homepage: "https://example.com/"
# Setting this will prevent goreleaser to actually try to commit the updated
# formula - instead, the formula file will be stored on the dist folder only,
# leaving the responsibility of publishing it to the user.
# If set to auto, the release will not be uploaded to the homebrew tap
# in case there is an indicator for prerelease in the tag e.g. v1.0.0-rc1
# Default is false.
skip_upload: true
# Your app's description.
# Default is empty.
description: "Software to create fast and easy drum rolls."
# Custom block for brew.
# Can be used to specify alternate downloads for devel or head releases.
# Default is empty.
custom_block: |
head "https://github.com/some/package.git"
...
# Setting this will prevent goreleaser to actually try to commit the updated
# formula - instead, the formula file will be stored on the dist folder only,
# leaving the responsibility of publishing it to the user.
# If set to auto, the release will not be uploaded to the homebrew tap
# in case there is an indicator for prerelease in the tag e.g. v1.0.0-rc1
# Default is false.
skip_upload: true
# Packages your package depends on.
dependencies:
- git
- zsh
# Custom block for brew.
# Can be used to specify alternate downloads for devel or head releases.
# Default is empty.
custom_block: |
head "https://github.com/some/package.git"
...
# Packages that conflict with your package.
conflicts:
- svn
- bash
# Packages your package depends on.
dependencies:
- git
- zsh
# Specify for packages that run as a service.
# Default is empty.
plist: |
<?xml version="1.0" encoding="UTF-8"?>
...
# Packages that conflict with your package.
conflicts:
- svn
- bash
# So you can `brew test` your formula.
# Default is empty.
test: |
system "#{bin}/program --version"
...
# Specify for packages that run as a service.
# Default is empty.
plist: |
<?xml version="1.0" encoding="UTF-8"?>
...
# Custom install script for brew.
# Default is 'bin.install "program"'.
install: |
bin.install "program"
...
# So you can `brew test` your formula.
# Default is empty.
test: |
system "#{bin}/program --version"
...
# Custom install script for brew.
# Default is 'bin.install "program"'.
install: |
bin.install "program"
...
```
> Learn more about the [name template engine](/templates).
@@ -116,9 +123,15 @@ Assuming that the current tag is `v1.2.3`, the above configuration will generate
class Program < Formula
desc "How to use this binary"
homepage "https://github.com/user/repo"
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_macOs_64bit.zip"
version "v1.2.3"
sha256 "9ee30fc358fae8d248a2d7538957089885da321dca3f09e3296fe2058e7fff74"
if os.Mac?
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_macOs_64bit.zip"
sha256 "9ee30fc358fae8d248a2d7538957089885da321dca3f09e3296fe2058e7fff74"
elsif os.Linux?
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_Linux_64bit.zip"
sha256 "b41bebd25fd7bb1a67dc2cd5ee12c9f67073094567fdf7b3871f05fd74a45fdd"
end
depends_on "git"
depends_on "zsh"
@@ -129,7 +142,7 @@ class Program < Formula
end
```
**Important**: Note that GoReleaser does not yet generate a valid
**Important**: Note that GoReleaser does not generate a valid
homebrew-core formula. The generated formulas are meant to be published as
[homebrew taps](https://docs.brew.sh/Taps.html), and in their current
form will not be accepted in any of the official homebrew repositories.