github.com/droot/goreleaser@v0.66.2-0.20180420030140-c2db5fb17157/internal/builders/golang/build_test.go (about) 1 package golang 2 3 import ( 4 "io/ioutil" 5 "path/filepath" 6 "runtime" 7 "strings" 8 "testing" 9 10 api "github.com/goreleaser/goreleaser/build" 11 "github.com/goreleaser/goreleaser/config" 12 "github.com/goreleaser/goreleaser/context" 13 "github.com/goreleaser/goreleaser/internal/artifact" 14 "github.com/goreleaser/goreleaser/internal/testlib" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 var runtimeTarget = runtime.GOOS + "_" + runtime.GOARCH 19 20 func TestWithDefaults(t *testing.T) { 21 for name, testcase := range map[string]struct { 22 build config.Build 23 targets []string 24 }{ 25 "full": { 26 build: config.Build{ 27 Binary: "foo", 28 Goos: []string{ 29 "linux", 30 "windows", 31 "darwin", 32 }, 33 Goarch: []string{ 34 "amd64", 35 "arm", 36 }, 37 Goarm: []string{ 38 "6", 39 }, 40 }, 41 targets: []string{ 42 "linux_amd64", 43 "darwin_amd64", 44 "windows_amd64", 45 "linux_arm_6", 46 }, 47 }, 48 "empty": { 49 build: config.Build{ 50 Binary: "foo", 51 }, 52 targets: []string{ 53 "linux_amd64", 54 "linux_386", 55 "darwin_amd64", 56 "darwin_386", 57 }, 58 }, 59 } { 60 t.Run(name, func(tt *testing.T) { 61 var config = config.Project{ 62 Builds: []config.Build{ 63 testcase.build, 64 }, 65 } 66 var ctx = context.New(config) 67 var build = Default.WithDefaults(ctx.Config.Builds[0]) 68 assert.ElementsMatch(t, build.Targets, testcase.targets) 69 }) 70 } 71 } 72 73 func TestBuild(t *testing.T) { 74 folder, back := testlib.Mktmp(t) 75 defer back() 76 writeGoodMain(t, folder) 77 var config = config.Project{ 78 Builds: []config.Build{ 79 { 80 Binary: "foo", 81 Targets: []string{ 82 "linux_amd64", 83 "darwin_amd64", 84 "windows_amd64", 85 "linux_arm_6", 86 }, 87 }, 88 }, 89 } 90 var ctx = context.New(config) 91 var build = ctx.Config.Builds[0] 92 for _, target := range build.Targets { 93 var ext string 94 if strings.HasPrefix(target, "windows") { 95 ext = ".exe" 96 } 97 var err = Default.Build(ctx, build, api.Options{ 98 Target: target, 99 Name: build.Binary, 100 Path: filepath.Join(folder, "dist", target, build.Binary), 101 Ext: ext, 102 }) 103 assert.NoError(t, err) 104 } 105 assert.ElementsMatch(t, ctx.Artifacts.List(), []artifact.Artifact{ 106 { 107 Name: "foo", 108 Path: filepath.Join(folder, "dist", "linux_amd64", "foo"), 109 Goos: "linux", 110 Goarch: "amd64", 111 Type: artifact.Binary, 112 Extra: map[string]string{ 113 "Ext": "", 114 "Binary": "foo", 115 }, 116 }, 117 { 118 Name: "foo", 119 Path: filepath.Join(folder, "dist", "darwin_amd64", "foo"), 120 Goos: "darwin", 121 Goarch: "amd64", 122 Type: artifact.Binary, 123 Extra: map[string]string{ 124 "Ext": "", 125 "Binary": "foo", 126 }, 127 }, 128 { 129 Name: "foo", 130 Path: filepath.Join(folder, "dist", "linux_arm_6", "foo"), 131 Goos: "linux", 132 Goarch: "arm", 133 Goarm: "6", 134 Type: artifact.Binary, 135 Extra: map[string]string{ 136 "Ext": "", 137 "Binary": "foo", 138 }, 139 }, 140 { 141 Name: "foo", 142 Path: filepath.Join(folder, "dist", "windows_amd64", "foo"), 143 Goos: "windows", 144 Goarch: "amd64", 145 Type: artifact.Binary, 146 Extra: map[string]string{ 147 "Ext": ".exe", 148 "Binary": "foo", 149 }, 150 }, 151 }) 152 } 153 154 func TestBuildFailed(t *testing.T) { 155 folder, back := testlib.Mktmp(t) 156 defer back() 157 writeGoodMain(t, folder) 158 var config = config.Project{ 159 Builds: []config.Build{ 160 { 161 Flags: "-flag-that-dont-exists-to-force-failure", 162 Targets: []string{ 163 runtimeTarget, 164 }, 165 }, 166 }, 167 } 168 var ctx = context.New(config) 169 var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 170 Target: "darwin_amd64", 171 }) 172 assertContainsError(t, err, `flag provided but not defined: -flag-that-dont-exists-to-force-failure`) 173 assert.Empty(t, ctx.Artifacts.List()) 174 } 175 176 func TestBuildInvalidTarget(t *testing.T) { 177 folder, back := testlib.Mktmp(t) 178 defer back() 179 writeGoodMain(t, folder) 180 var target = "linux" 181 var config = config.Project{ 182 Builds: []config.Build{ 183 { 184 Binary: "foo", 185 Targets: []string{target}, 186 }, 187 }, 188 } 189 var ctx = context.New(config) 190 var build = ctx.Config.Builds[0] 191 var err = Default.Build(ctx, build, api.Options{ 192 Target: target, 193 Name: build.Binary, 194 Path: filepath.Join(folder, "dist", target, build.Binary), 195 }) 196 assert.EqualError(t, err, "linux is not a valid build target") 197 assert.Len(t, ctx.Artifacts.List(), 0) 198 } 199 200 func TestRunInvalidLdflags(t *testing.T) { 201 folder, back := testlib.Mktmp(t) 202 defer back() 203 writeGoodMain(t, folder) 204 var config = config.Project{ 205 Builds: []config.Build{ 206 { 207 Binary: "nametest", 208 Flags: "-v", 209 Ldflags: "-s -w -X main.version={{.Version}", 210 Targets: []string{ 211 runtimeTarget, 212 }, 213 }, 214 }, 215 } 216 var ctx = context.New(config) 217 var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 218 Target: runtimeTarget, 219 }) 220 assert.EqualError(t, err, `template: ldflags:1: unexpected "}" in operand`) 221 } 222 223 func TestRunPipeWithoutMainFunc(t *testing.T) { 224 folder, back := testlib.Mktmp(t) 225 defer back() 226 writeMainWithoutMainFunc(t, folder) 227 var config = config.Project{ 228 Builds: []config.Build{ 229 { 230 Binary: "no-main", 231 Hooks: config.Hooks{}, 232 Targets: []string{ 233 runtimeTarget, 234 }, 235 }, 236 }, 237 } 238 var ctx = context.New(config) 239 t.Run("empty", func(t *testing.T) { 240 ctx.Config.Builds[0].Main = "" 241 assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 242 Target: runtimeTarget, 243 }), `build for no-main does not contain a main function`) 244 }) 245 t.Run("not main.go", func(t *testing.T) { 246 ctx.Config.Builds[0].Main = "foo.go" 247 assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 248 Target: runtimeTarget, 249 }), `stat foo.go: no such file or directory`) 250 }) 251 t.Run("glob", func(t *testing.T) { 252 ctx.Config.Builds[0].Main = "." 253 assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 254 Target: runtimeTarget, 255 }), `build for no-main does not contain a main function`) 256 }) 257 t.Run("fixed main.go", func(t *testing.T) { 258 ctx.Config.Builds[0].Main = "main.go" 259 assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 260 Target: runtimeTarget, 261 }), `build for no-main does not contain a main function`) 262 }) 263 } 264 265 func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) { 266 folder, back := testlib.Mktmp(t) 267 defer back() 268 assert.NoError(t, ioutil.WriteFile( 269 filepath.Join(folder, "foo.go"), 270 []byte("package main\nfunc main() {println(0)}"), 271 0644, 272 )) 273 var config = config.Project{ 274 Builds: []config.Build{ 275 { 276 Binary: "foo", 277 Hooks: config.Hooks{}, 278 Targets: []string{ 279 runtimeTarget, 280 }, 281 }, 282 }, 283 } 284 var ctx = context.New(config) 285 t.Run("empty", func(t *testing.T) { 286 ctx.Config.Builds[0].Main = "" 287 assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 288 Target: runtimeTarget, 289 })) 290 }) 291 t.Run("foo.go", func(t *testing.T) { 292 ctx.Config.Builds[0].Main = "foo.go" 293 assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 294 Target: runtimeTarget, 295 })) 296 }) 297 t.Run("glob", func(t *testing.T) { 298 ctx.Config.Builds[0].Main = "." 299 assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 300 Target: runtimeTarget, 301 })) 302 }) 303 } 304 305 func TestLdFlagsFullTemplate(t *testing.T) { 306 var config = config.Project{ 307 Builds: []config.Build{ 308 { 309 Ldflags: `-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}" -X main.time={{ time "20060102" }}`, 310 }, 311 }, 312 } 313 var ctx = &context.Context{ 314 Git: context.GitInfo{ 315 CurrentTag: "v1.2.3", 316 Commit: "123", 317 }, 318 Version: "1.2.3", 319 Config: config, 320 Env: map[string]string{"FOO": "123"}, 321 } 322 flags, err := ldflags(ctx, ctx.Config.Builds[0]) 323 assert.NoError(t, err) 324 assert.Contains(t, flags, "-s -w") 325 assert.Contains(t, flags, "-X main.version=1.2.3") 326 assert.Contains(t, flags, "-X main.tag=v1.2.3") 327 assert.Contains(t, flags, "-X main.commit=123") 328 // TODO: this will break in 2019 329 assert.Contains(t, flags, "-X main.date=2018") 330 assert.Contains(t, flags, "-X main.time=2018") 331 assert.Contains(t, flags, `-X "main.foo=123"`) 332 } 333 334 func TestInvalidTemplate(t *testing.T) { 335 for template, eerr := range map[string]string{ 336 "{{ .Nope }": `template: ldflags:1: unexpected "}" in operand`, 337 "{{.Env.NOPE}}": `template: ldflags:1:6: executing "ldflags" at <.Env.NOPE>: map has no entry for key "NOPE"`, 338 } { 339 t.Run(template, func(tt *testing.T) { 340 var config = config.Project{ 341 Builds: []config.Build{ 342 {Ldflags: template}, 343 }, 344 } 345 var ctx = &context.Context{ 346 Config: config, 347 } 348 flags, err := ldflags(ctx, ctx.Config.Builds[0]) 349 assert.EqualError(tt, err, eerr) 350 assert.Empty(tt, flags) 351 }) 352 } 353 } 354 355 // 356 // Helpers 357 // 358 359 func writeMainWithoutMainFunc(t *testing.T, folder string) { 360 assert.NoError(t, ioutil.WriteFile( 361 filepath.Join(folder, "main.go"), 362 []byte("package main\nconst a = 2\nfunc notMain() {println(0)}"), 363 0644, 364 )) 365 } 366 367 func writeGoodMain(t *testing.T, folder string) { 368 assert.NoError(t, ioutil.WriteFile( 369 filepath.Join(folder, "main.go"), 370 []byte("package main\nvar a = 1\nfunc main() {println(0)}"), 371 0644, 372 )) 373 } 374 375 func assertContainsError(t *testing.T, err error, s string) { 376 assert.Error(t, err) 377 assert.Contains(t, err.Error(), s) 378 }