github.com/marianogappa/goreleaser@v0.26.2-0.20170715090149-96acd0a9fc46/pipeline/brew/brew.go (about) 1 // Package brew implements the Pipe, providing formula generation and 2 // uploading it to a configured repo. 3 package brew 4 5 import ( 6 "bytes" 7 "errors" 8 "path/filepath" 9 "strings" 10 "text/template" 11 12 "github.com/apex/log" 13 "github.com/goreleaser/goreleaser/checksum" 14 "github.com/goreleaser/goreleaser/config" 15 "github.com/goreleaser/goreleaser/context" 16 "github.com/goreleaser/goreleaser/internal/archiveformat" 17 "github.com/goreleaser/goreleaser/internal/client" 18 ) 19 20 // ErrNoDarwin64Build when there is no build for darwin_amd64 (goos doesn't 21 // contain darwin and/or goarch doesn't contain amd64) 22 var ErrNoDarwin64Build = errors.New("brew tap requires a darwin amd64 build") 23 24 const platform = "darwinamd64" 25 26 const formula = `class {{ .Name }} < Formula 27 desc "{{ .Desc }}" 28 homepage "{{ .Homepage }}" 29 url "https://github.com/{{ .Repo.Owner }}/{{ .Repo.Name }}/releases/download/{{ .Tag }}/{{ .File }}" 30 version "{{ .Version }}" 31 sha256 "{{ .SHA256 }}" 32 33 {{- if .Dependencies }} 34 {{ range $index, $element := .Dependencies }} 35 depends_on "{{ . }}" 36 {{- end }} 37 {{- end }} 38 39 {{- if .Conflicts }} 40 {{ range $index, $element := .Conflicts }} 41 conflicts_with "{{ . }}" 42 {{- end }} 43 {{- end }} 44 45 def install 46 {{- range $index, $element := .Install }} 47 {{ . -}} 48 {{- end }} 49 end 50 51 {{- if .Caveats }} 52 53 def caveats 54 "{{ .Caveats }}" 55 end 56 {{- end }} 57 58 {{- if .Plist }} 59 60 def plist; <<-EOS.undent 61 {{ .Plist }} 62 EOS 63 end 64 {{- end }} 65 end 66 ` 67 68 type templateData struct { 69 Name string 70 Desc string 71 Homepage string 72 Repo config.Repo // FIXME: will not work for anything but github right now. 73 Tag string 74 Version string 75 Caveats string 76 File string 77 SHA256 string 78 Plist string 79 Install []string 80 Dependencies []string 81 Conflicts []string 82 } 83 84 // Pipe for brew deployment 85 type Pipe struct{} 86 87 // Description of the pipe 88 func (Pipe) Description() string { 89 return "Creating homebrew formula" 90 } 91 92 // Run the pipe 93 func (Pipe) Run(ctx *context.Context) error { 94 return doRun(ctx, client.NewGitHub(ctx)) 95 } 96 97 func doRun(ctx *context.Context, client client.Client) error { 98 if !ctx.Publish { 99 log.Warn("skipped because --skip-publish is set") 100 return nil 101 } 102 if ctx.Config.Brew.GitHub.Name == "" { 103 log.Warn("skipped because brew section is not configured") 104 return nil 105 } 106 if ctx.Config.Release.Draft { 107 log.Warn("skipped because release is marked as draft") 108 return nil 109 } 110 if ctx.Config.Archive.Format == "binary" { 111 log.Info("skipped because archive format is binary") 112 return nil 113 } 114 var path = filepath.Join(ctx.Config.Brew.Folder, ctx.Config.ProjectName+".rb") 115 log.WithField("formula", path). 116 WithField("repo", ctx.Config.Brew.GitHub.String()). 117 Info("pushing") 118 content, err := buildFormula(ctx, client) 119 if err != nil { 120 return err 121 } 122 return client.CreateFile(ctx, content, path) 123 } 124 125 func buildFormula(ctx *context.Context, client client.Client) (bytes.Buffer, error) { 126 data, err := dataFor(ctx, client) 127 if err != nil { 128 return bytes.Buffer{}, err 129 } 130 return doBuildFormula(data) 131 } 132 133 func doBuildFormula(data templateData) (bytes.Buffer, error) { 134 var out bytes.Buffer 135 tmpl, err := template.New(data.Name).Parse(formula) 136 if err != nil { 137 return out, err 138 } 139 err = tmpl.Execute(&out, data) 140 return out, err 141 } 142 143 func dataFor(ctx *context.Context, client client.Client) (result templateData, err error) { 144 var folder = ctx.Folders[platform] 145 if folder == "" { 146 return result, ErrNoDarwin64Build 147 } 148 var file = folder + "." + archiveformat.For(ctx, platform) 149 sum, err := checksum.SHA256(filepath.Join(ctx.Config.Dist, file)) 150 if err != nil { 151 return 152 } 153 return templateData{ 154 Name: formulaNameFor(ctx.Config.ProjectName), 155 Desc: ctx.Config.Brew.Description, 156 Homepage: ctx.Config.Brew.Homepage, 157 Repo: ctx.Config.Release.GitHub, 158 Tag: ctx.Git.CurrentTag, 159 Version: ctx.Version, 160 Caveats: ctx.Config.Brew.Caveats, 161 File: file, 162 SHA256: sum, 163 Dependencies: ctx.Config.Brew.Dependencies, 164 Conflicts: ctx.Config.Brew.Conflicts, 165 Plist: ctx.Config.Brew.Plist, 166 Install: strings.Split(ctx.Config.Brew.Install, "\n"), 167 }, err 168 } 169 170 func formulaNameFor(name string) string { 171 name = strings.Replace(name, "-", " ", -1) 172 name = strings.Replace(name, "_", " ", -1) 173 return strings.Replace(strings.Title(name), " ", "", -1) 174 }