diff --git a/internal/builders/golang/build.go b/internal/builders/golang/build.go index 6c53b2eff36b..7c24dc86764b 100644 --- a/internal/builders/golang/build.go +++ b/internal/builders/golang/build.go @@ -165,7 +165,23 @@ func (*Builder) Build(ctx *context.Context, build config.Build, options api.Opti return err } - env := append(ctx.Env.Strings(), details.Env...) + env := []string{} + // used for unit testing only + testEnvs := []string{} + env = append(env, ctx.Env.Strings()...) + for _, e := range details.Env { + ee, err := tmpl.New(ctx).WithEnvS(env).WithArtifact(a, nil).Apply(e) + if err != nil { + return err + } + log.Debugf("env %q evaluated to %q", e, ee) + if ee != "" { + env = append(env, ee) + if strings.HasPrefix(e, "TEST_") { + testEnvs = append(testEnvs, ee) + } + } + } env = append( env, "GOOS="+options.Goos, @@ -176,6 +192,10 @@ func (*Builder) Build(ctx *context.Context, build config.Build, options api.Opti "GOAMD64="+options.Goamd64, ) + if len(testEnvs) > 0 { + a.Extra["testEnvs"] = testEnvs + } + cmd, err := buildGoBuildLine(ctx, build, details, options, a, env) if err != nil { return err diff --git a/internal/builders/golang/build_test.go b/internal/builders/golang/build_test.go index 4ddfe5a75dad..aa55c001763e 100644 --- a/internal/builders/golang/build_test.go +++ b/internal/builders/golang/build_test.go @@ -363,7 +363,16 @@ func TestBuild(t *testing.T) { GoBinary: "go", Command: "build", BuildDetails: config.BuildDetails{ - Env: []string{"GO111MODULE=off"}, + Env: []string{ + "GO111MODULE=off", + `TEST_T={{- if eq .Os "windows" -}} + w + {{- else if eq .Os "darwin" -}} + d + {{- else if eq .Os "linux" -}} + l + {{- end -}}`, + }, Asmflags: []string{".=", "all="}, Gcflags: []string{"all="}, Flags: []string{"{{.Env.GO_FLAGS}}"}, @@ -426,6 +435,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: "", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T=l"}, }, }, { @@ -439,6 +449,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: "", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T=l"}, }, }, { @@ -452,6 +463,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: "", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T=l"}, }, }, { @@ -464,6 +476,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: "", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T=d"}, }, }, { @@ -477,6 +490,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: "", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T=l"}, }, }, { @@ -489,6 +503,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: ".exe", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T=w"}, }, }, { @@ -501,6 +516,7 @@ func TestBuild(t *testing.T) { artifact.ExtraExt: ".wasm", artifact.ExtraBinary: "foo-v5.6.7", artifact.ExtraID: "foo", + "testEnvs": []string{"TEST_T="}, }, }, }) @@ -524,6 +540,37 @@ func TestBuild(t *testing.T) { } } +func TestBuildInvalidEnv(t *testing.T) { + folder := testlib.Mktmp(t) + writeGoodMain(t, folder) + config := config.Project{ + Builds: []config.Build{ + { + ID: "foo", + Dir: ".", + Binary: "foo", + Targets: []string{ + runtimeTarget, + }, + GoBinary: "go", + BuildDetails: config.BuildDetails{ + Env: []string{"GO111MODULE={{ .Nope }}"}, + }, + }, + }, + } + ctx := context.New(config) + ctx.Git.CurrentTag = "5.6.7" + build := ctx.Config.Builds[0] + err := Default.Build(ctx, build, api.Options{ + Target: runtimeTarget, + Name: build.Binary, + Path: filepath.Join(folder, "dist", runtimeTarget, build.Binary), + Ext: "", + }) + testlib.RequireTemplateError(t, err) +} + func TestBuildCodeInSubdir(t *testing.T) { folder := testlib.Mktmp(t) subdir := filepath.Join(folder, "bar") diff --git a/internal/pipe/build/build.go b/internal/pipe/build/build.go index d2ae35d53c83..137f6826a196 100644 --- a/internal/pipe/build/build.go +++ b/internal/pipe/build/build.go @@ -115,9 +115,7 @@ func runHook(ctx *context.Context, opts builders.Options, buildEnv []string, hoo var env []string env = append(env, ctx.Env.Strings()...) - env = append(env, buildEnv...) - - for _, rawEnv := range hook.Env { + for _, rawEnv := range append(buildEnv, hook.Env...) { e, err := tmpl.New(ctx).WithBuildOptions(opts).Apply(rawEnv) if err != nil { return err diff --git a/internal/pipe/build/build_test.go b/internal/pipe/build/build_test.go index f89a8acdfcb5..1fea450bf70f 100644 --- a/internal/pipe/build/build_test.go +++ b/internal/pipe/build/build_test.go @@ -121,6 +121,8 @@ func TestRunFullPipe(t *testing.T) { folder := testlib.Mktmp(t) pre := filepath.Join(folder, "pre") post := filepath.Join(folder, "post") + preOS := filepath.Join(folder, "pre_linux") + postOS := filepath.Join(folder, "post_linux") config := config.Project{ Builds: []config.Build{ { @@ -130,13 +132,16 @@ func TestRunFullPipe(t *testing.T) { BuildDetails: config.BuildDetails{ Flags: []string{"-v"}, Ldflags: []string{"-X main.test=testing"}, + Env: []string{"THE_OS={{ .Os }}"}, }, Hooks: config.BuildHookConfig{ Pre: []config.Hook{ {Cmd: "touch " + pre}, + {Cmd: "touch pre_{{ .Env.THE_OS}}"}, }, Post: []config.Hook{ {Cmd: "touch " + post}, + {Cmd: "touch post_{{ .Env.THE_OS}}"}, }, }, Targets: []string{"linux_amd64"}, @@ -153,6 +158,8 @@ func TestRunFullPipe(t *testing.T) { }}) require.FileExists(t, post) require.FileExists(t, pre) + require.FileExists(t, postOS) + require.FileExists(t, preOS) require.FileExists(t, filepath.Join(folder, "build1_linux_amd64", "testing")) } diff --git a/www/docs/customization/build.md b/www/docs/customization/build.md index 472cf50c1972..f9a512c7e7f4 100644 --- a/www/docs/customization/build.md +++ b/www/docs/customization/build.md @@ -70,10 +70,20 @@ builds: - feature # Custom environment variables to be set during the builds. + # This field is templateable. Since v1.14. # # Default: `os.Environ()` merged with what you set the root `env` section. env: - CGO_ENABLED=0 + # complex, templated envs: + - >- + {{- if eq .Os "darwin" }} + {{- if eq .Arch "amd64"}}CC=o64-clang{{- end }} + {{- if eq .Arch "arm64"}}CC=aarch64-apple-darwin20.2-clang{{- end }} + {{- end }} + {{- if eq .Os "windows" }} + {{- if eq .Arch "amd64" }}CC=x86_64-w64-mingw32-gcc{{- end }} + {{- end }} # GOOS list to build for. # For more info refer to: https://golang.org/doc/install/source#environment @@ -556,3 +566,83 @@ builds: # Configure the buildmode flag to output a shared library buildmode: "c-shared" # or "c-archive" for a static library ``` + +## Complex templated environment variables + +> Since v1.14. + +Builds environment variables are templateable. + +You can leverage that to have a single build configuration with different +environment variables for each platform, for example. + +A common example of this is the variables `CC` and `CCX`. + +Here are two different examples: + +### Using multiple envs + +This example creates once `CC_` and `CCX_` variable for each platform, and then +set `CC` and `CCX` to the right one: + +```yaml +# .goreleaser.yml +builds: +- id: mybin + binary: mybin + main: . + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + env: + - CGO_ENABLED=0 + - CC_darwin_amd64=o64-clang + - CCX_darwin_amd64=o64-clang+ + - CC_darwin_arm64=aarch64-apple-darwin20.2-clang + - CCX_darwin_arm64=aarch64-apple-darwin20.2-clang++ + - CC_windows_amd64=x86_64-w64-mingw32-gc + - CCX_windows_amd64=x86_64-w64-mingw32-g++ + - 'CC={{ index .Env (print "CC_" .Os "_" .Arch) }}' + - 'CCX={{ index .Env (print "CCX_" .Os "_" .Arch) }}' +``` + +### Using `if` statements + +This example uses `if` statements to set `CC` and `CCX`: + +```yaml +# .goreleaser.yml +builds: +- id: mybin + binary: mybin + main: . + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + env: + - CGO_ENABLED=0 + - >- + {{- if eq .Os "darwin" }} + {{- if eq .Arch "amd64"}}CC=o64-clang{{- end }} + {{- if eq .Arch "arm64"}}CC=aarch64-apple-darwin20.2-clang{{- end }} + {{- end }} + {{- if eq .Os "windows" }} + {{- if eq .Arch "amd64" }}CC=x86_64-w64-mingw32-gcc{{- end }} + {{- end }} + - >- + {{- if eq .Os "darwin" }} + {{- if eq .Arch "amd64"}}CXX=o64-clang+{{- end }} + {{- if eq .Arch "arm64"}}CXX=aarch64-apple-darwin20.2-clang++{{- end }} + {{- end }} + {{- if eq .Os "windows" }} + {{- if eq .Arch "amd64" }}CXX=x86_64-w64-mingw32-g++{{- end }} + {{- end }} +```