Repository: goreleaser/goreleaser
Pull request #2475 (2021-09-11 03:47:08)

refactor: improve build
prepare the build api for future features:

- move matrix gen to another pkg
- merge target stuff with build opts
- renamed `builds.lang` to `builds.builder`


vercel[bot]: This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).  
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: [https://vercel.com/goreleaser/goreleaser/3tyUBGSM3HCtCGA7RoLBFM5FsJ1v](https://vercel.com/goreleaser/goreleaser/3tyUBGSM3HCtCGA7RoLBFM5FsJ1v)  
✅ Preview: *In Progress*


codecov[bot]: # [Codecov](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) Report
> Merging [#2475](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (33ed61f) into [master](https://codecov.io/gh/goreleaser/goreleaser/commit/8241a23e439a2d67c77bb86c6532b52ae4268afe?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (8241a23) will **decrease** coverage by `0.29%`.
> The diff coverage is `88.00%`.

[![Impacted file tree graph](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/graphs/tree.svg?width=650&height=150&src=pr&token=3bJvv6b7hN&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)

```diff
@@            Coverage Diff             @@
##           master    #2475      +/-   ##
==========================================
- Coverage   84.49%   84.19%   -0.30%     
==========================================
  Files          88       88              
  Lines        6340     6335       -5     
==========================================
- Hits         5357     5334      -23     
- Misses        827      840      +13     
- Partials      156      161       +5     
```


| [Impacted Files](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | Coverage Δ | |
|---|---|---|
| [pkg/config/config.go](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-cGtnL2NvbmZpZy9jb25maWcuZ28=) | `90.72% <ø> (ø)` | |
| [internal/builders/buildtarget/targets.go](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvYnVpbGRlcnMvYnVpbGR0YXJnZXQvdGFyZ2V0cy5nbw==) | `94.69% <50.00%> (ø)` | |
| [internal/pipe/build/build.go](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9idWlsZC9idWlsZC5nbw==) | `88.77% <86.95%> (-9.53%)` | :arrow_down: |
| [internal/builders/golang/build.go](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvYnVpbGRlcnMvZ29sYW5nL2J1aWxkLmdv) | `92.14% <100.00%> (+0.51%)` | :arrow_up: |
| [internal/tmpl/tmpl.go](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvdG1wbC90bXBsLmdv) | `95.83% <100.00%> (+0.07%)` | :arrow_up: |
| [pkg/build/build.go](https://codecov.io/gh/goreleaser/goreleaser/pull/2475/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-cGtnL2J1aWxkL2J1aWxkLmdv) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser). Last update [8241a23...33ed61f](https://codecov.io/gh/goreleaser/goreleaser/pull/2475?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser).


Patch:
diff --git a/internal/builders/golang/targets.go b/internal/builders/buildtarget/targets.go
similarity index 96%
rename from internal/builders/golang/targets.go
rename to internal/builders/buildtarget/targets.go
index cafaa07f..1a61e766 100644
--- a/internal/builders/golang/targets.go
+++ b/internal/builders/buildtarget/targets.go
@@ -1,4 +1,4 @@
-package golang
+package buildtarget
 
 import (
 	"fmt"
@@ -26,6 +26,14 @@ func (t target) String() string {
 	return fmt.Sprintf("%s_%s", t.os, t.arch)
 }
 
+func Matrix(build config.Build) ([]string, error) {
+	version, err := goVersion(build)
+	if err != nil {
+		return nil, err
+	}
+	return matrix(build, version)
+}
+
 func matrix(build config.Build, version []byte) ([]string, error) {
 	// nolint:prealloc
 	var targets []target
diff --git a/internal/builders/buildtarget/testdata/.gitkeep b/internal/builders/buildtarget/testdata/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/builders/golang/build.go b/internal/builders/golang/build.go
index 49826fba..2e67603b 100644
--- a/internal/builders/golang/build.go
+++ b/internal/builders/golang/build.go
@@ -14,6 +14,7 @@ import (
 
 	"github.com/apex/log"
 	"github.com/goreleaser/goreleaser/internal/artifact"
+	"github.com/goreleaser/goreleaser/internal/builders/buildtarget"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	api "github.com/goreleaser/goreleaser/pkg/build"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -59,11 +60,7 @@ func (*Builder) WithDefaults(build config.Build) (config.Build, error) {
 		if len(build.Gomips) == 0 {
 			build.Gomips = []string{"hardfloat"}
 		}
-		version, err := goVersion(build)
-		if err != nil {
-			return build, err
-		}
-		targets, err := matrix(build, version)
+		targets, err := buildtarget.Matrix(build)
 		build.Targets = targets
 		if err != nil {
 			return build, err
@@ -77,19 +74,15 @@ func (*Builder) Build(ctx *context.Context, build config.Build, options api.Opti
 	if err := checkMain(build); err != nil {
 		return err
 	}
-	target, err := newBuildTarget(options.Target)
-	if err != nil {
-		return err
-	}
 
 	artifact := &artifact.Artifact{
 		Type:   artifact.Binary,
 		Path:   options.Path,
 		Name:   options.Name,
-		Goos:   target.os,
-		Goarch: target.arch,
-		Goarm:  target.arm,
-		Gomips: target.mips,
+		Goos:   options.Goos,
+		Goarch: options.Goarch,
+		Goarm:  options.Goarm,
+		Gomips: options.Gomips,
 		Extra: map[string]interface{}{
 			"Binary": strings.TrimSuffix(filepath.Base(options.Path), options.Ext),
 			"Ext":    options.Ext,
@@ -98,7 +91,14 @@ func (*Builder) Build(ctx *context.Context, build config.Build, options api.Opti
 	}
 
 	env := append(ctx.Env.Strings(), build.Env...)
-	env = append(env, target.Env()...)
+	env = append(
+		env,
+		"GOOS="+options.Goos,
+		"GOARCH="+options.Goarch,
+		"GOARM="+options.Goarm,
+		"GOMIPS="+options.Gomips,
+		"GOMIPS64="+options.Gomips,
+	)
 
 	cmd, err := buildGoBuildLine(ctx, build, options, artifact, env)
 	if err != nil {
@@ -202,37 +202,6 @@ func run(ctx *context.Context, command, env []string, dir string) error {
 	return nil
 }
 
-type buildTarget struct {
-	os, arch, arm, mips string
-}
-
-func newBuildTarget(s string) (buildTarget, error) {
-	t := buildTarget{}
-	parts := strings.Split(s, "_")
-	if len(parts) < 2 {
-		return t, fmt.Errorf("%s is not a valid build target", s)
-	}
-	t.os = parts[0]
-	t.arch = parts[1]
-	if strings.HasPrefix(t.arch, "arm") && len(parts) == 3 {
-		t.arm = parts[2]
-	}
-	if strings.HasPrefix(t.arch, "mips") && len(parts) == 3 {
-		t.mips = parts[2]
-	}
-	return t, nil
-}
-
-func (b buildTarget) Env() []string {
-	return []string{
-		"GOOS=" + b.os,
-		"GOARCH=" + b.arch,
-		"GOARM=" + b.arm,
-		"GOMIPS=" + b.mips,
-		"GOMIPS64=" + b.mips,
-	}
-}
-
 func checkMain(build config.Build) error {
 	main := build.Main
 	if build.UnproxiedMain != "" {
diff --git a/internal/pipe/build/build.go b/internal/pipe/build/build.go
index a9b8f2bb..9008acc6 100644
--- a/internal/pipe/build/build.go
+++ b/internal/pipe/build/build.go
@@ -70,8 +70,8 @@ func (Pipe) Default(ctx *context.Context) error {
 }
 
 func buildWithDefaults(ctx *context.Context, build config.Build) (config.Build, error) {
-	if build.Lang == "" {
-		build.Lang = "go"
+	if build.Builder == "" {
+		build.Builder = "go"
 	}
 	if build.Binary == "" {
 		build.Binary = ctx.Config.ProjectName
@@ -82,7 +82,7 @@ func buildWithDefaults(ctx *context.Context, build config.Build) (config.Build,
 	for k, v := range build.Env {
 		build.Env[k] = os.ExpandEnv(v)
 	}
-	return builders.For(build.Lang).WithDefaults(build)
+	return builders.For(build.Builder).WithDefaults(build)
 }
 
 func runPipeOnBuild(ctx *context.Context, build config.Build) error {
@@ -160,24 +160,35 @@ func runHook(ctx *context.Context, opts builders.Options, buildEnv []string, hoo
 }
 
 func doBuild(ctx *context.Context, build config.Build, opts builders.Options) error {
-	return builders.For(build.Lang).Build(ctx, build, opts)
+	return builders.For(build.Builder).Build(ctx, build, opts)
 }
 
 func buildOptionsForTarget(ctx *context.Context, build config.Build, target string) (*builders.Options, error) {
 	ext := extFor(target, build.Flags)
-	var goos string
-	var goarch string
+	parts := strings.Split(target, "_")
+	if len(parts) < 2 {
+		return nil, fmt.Errorf("%s is not a valid build target", target)
+	}
+
+	goos := parts[0]
+	goarch := parts[1]
 
-	if strings.Contains(target, "_") {
-		goos = strings.Split(target, "_")[0]
-		goarch = strings.Split(target, "_")[1]
+	var gomips string
+	var goarm string
+	if strings.HasPrefix(goarch, "arm") && len(parts) > 2 {
+		goarm = parts[2]
+	}
+	if strings.HasPrefix(goarch, "mips") && len(parts) > 2 {
+		gomips = parts[2]
 	}
 
 	buildOpts := builders.Options{
 		Target: target,
 		Ext:    ext,
-		Os:     goos,
-		Arch:   goarch,
+		Goos:   goos,
+		Goarch: goarch,
+		Goarm:  goarm,
+		Gomips: gomips,
 	}
 
 	binary, err := tmpl.New(ctx).WithBuildOptions(buildOpts).Apply(build.Binary)
@@ -201,10 +212,10 @@ func buildOptionsForTarget(ctx *context.Context, build config.Build, target stri
 	if err != nil {
 		return nil, err
 	}
+	buildOpts.Path = path
 
-	log.WithField("binary", path).Info("building")
+	log.WithField("binary", buildOpts.Path).Info("building")
 	buildOpts.Name = name
-	buildOpts.Path = path
 	return &buildOpts, nil
 }
 
diff --git a/internal/tmpl/tmpl.go b/internal/tmpl/tmpl.go
index 321751ae..b51cab50 100644
--- a/internal/tmpl/tmpl.go
+++ b/internal/tmpl/tmpl.go
@@ -146,8 +146,10 @@ func buildOptsToFields(opts build.Options) Fields {
 		ext:    opts.Ext,
 		name:   opts.Name,
 		path:   opts.Path,
-		osKey:  opts.Os,
-		arch:   opts.Arch,
+		osKey:  opts.Goos,
+		arch:   opts.Goarch,
+		arm:    opts.Goarm,
+		mips:   opts.Gomips,
 	}
 }
 
diff --git a/pkg/build/build.go b/pkg/build/build.go
index 6c7f5041..6b151ea1 100644
--- a/pkg/build/build.go
+++ b/pkg/build/build.go
@@ -14,21 +14,28 @@ var (
 	lock     sync.Mutex
 )
 
-// Register registers a builder to a given lang.
-func Register(lang string, builder Builder) {
+// Register registers a builder to a given name.
+func Register(name string, builder Builder) {
 	lock.Lock()
-	builders[lang] = builder
+	builders[name] = builder
 	lock.Unlock()
 }
 
-// For gets the previously registered builder for the given lang.
-func For(lang string) Builder {
-	return builders[lang]
+// For gets the previously registered builder for the given name.
+func For(name string) Builder {
+	return builders[name]
 }
 
 // Options to be passed down to a builder.
 type Options struct {
-	Name, Path, Ext, Target, Os, Arch string
+	Name   string
+	Path   string
+	Ext    string
+	Target string
+	Goos   string
+	Goarch string
+	Goarm  string
+	Gomips string
 }
 
 // Builder defines a builder.
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 06413757..f2b8fdd7 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -201,7 +201,7 @@ type Build struct {
 	Binary          string         `yaml:",omitempty"`
 	Hooks           HookConfig     `yaml:",omitempty"`
 	Env             []string       `yaml:",omitempty"`
-	Lang            string         `yaml:",omitempty"`
+	Builder         string         `yaml:",omitempty"`
 	Asmflags        StringArray    `yaml:",omitempty"`
 	Gcflags         StringArray    `yaml:",omitempty"`
 	ModTimestamp    string         `yaml:"mod_timestamp,omitempty"`


Test patch:
diff --git a/internal/builders/golang/targets_test.go b/internal/builders/buildtarget/targets_test.go
similarity index 99%
rename from internal/builders/golang/targets_test.go
rename to internal/builders/buildtarget/targets_test.go
index c518b366..c62972f1 100644
--- a/internal/builders/golang/targets_test.go
+++ b/internal/builders/buildtarget/targets_test.go
@@ -1,4 +1,4 @@
-package golang
+package buildtarget
 
 import (
 	"fmt"
diff --git a/internal/builders/golang/build_test.go b/internal/builders/golang/build_test.go
index 078e5452..7b3044c4 100644
--- a/internal/builders/golang/build_test.go
+++ b/internal/builders/golang/build_test.go
@@ -252,10 +252,27 @@ func TestBuild(t *testing.T) {
 		// injecting some delay here to force inconsistent mod times on bins
 		time.Sleep(2 * time.Second)
 
+		parts := strings.Split(target, "_")
+		goos := parts[0]
+		goarch := parts[1]
+		goarm := ""
+		gomips := ""
+		if len(parts) > 2 {
+			if strings.Contains(goarch, "arm") {
+				goarm = parts[2]
+			}
+			if strings.Contains(goarch, "mips") {
+				gomips = parts[2]
+			}
+		}
 		err := Default.Build(ctx, build, api.Options{
 			Target: target,
 			Name:   bin + ext,
 			Path:   filepath.Join(folder, "dist", target, bin+ext),
+			Goos:   goos,
+			Goarch: goarch,
+			Goarm:  goarm,
+			Gomips: gomips,
 			Ext:    ext,
 		})
 		require.NoError(t, err)
@@ -451,31 +468,6 @@ func TestBuildFailed(t *testing.T) {
 	require.Empty(t, ctx.Artifacts.List())
 }
 
-func TestBuildInvalidTarget(t *testing.T) {
-	folder := testlib.Mktmp(t)
-	writeGoodMain(t, folder)
-	target := "linux"
-	config := config.Project{
-		Builds: []config.Build{
-			{
-				ID:      "foo",
-				Binary:  "foo",
-				Targets: []string{target},
-			},
-		},
-	}
-	ctx := context.New(config)
-	ctx.Git.CurrentTag = "5.6.7"
-	build := ctx.Config.Builds[0]
-	err := Default.Build(ctx, build, api.Options{
-		Target: target,
-		Name:   build.Binary,
-		Path:   filepath.Join(folder, "dist", target, build.Binary),
-	})
-	require.EqualError(t, err, "linux is not a valid build target")
-	require.Len(t, ctx.Artifacts.List(), 0)
-}
-
 func TestRunInvalidAsmflags(t *testing.T) {
 	folder := testlib.Mktmp(t)
 	writeGoodMain(t, folder)
diff --git a/internal/pipe/build/build_test.go b/internal/pipe/build/build_test.go
index 2bd919b6..a5757790 100644
--- a/internal/pipe/build/build_test.go
+++ b/internal/pipe/build/build_test.go
@@ -2,7 +2,6 @@ package build
 
 import (
 	"errors"
-	"fmt"
 	"os"
 	"path/filepath"
 	"testing"
@@ -69,10 +68,10 @@ func TestBuild(t *testing.T) {
 		Dist: folder,
 		Builds: []config.Build{
 			{
-				Lang:   "fake",
-				Binary: "testing.v{{.Version}}",
-				Flags:  []string{"-n"},
-				Env:    []string{"BLAH=1"},
+				Builder: "fake",
+				Binary:  "testing.v{{.Version}}",
+				Flags:   []string{"-n"},
+				Env:     []string{"BLAH=1"},
 			},
 		},
 	}
@@ -97,11 +96,11 @@ func TestRunPipe(t *testing.T) {
 		Dist: folder,
 		Builds: []config.Build{
 			{
-				Lang:    "fake",
+				Builder: "fake",
 				Binary:  "testing",
 				Flags:   []string{"-v"},
 				Ldflags: []string{"-X main.test=testing"},
-				Targets: []string{"whatever"},
+				Targets: []string{"linux_amd64"},
 			},
 		},
 	}
@@ -121,7 +120,7 @@ func TestRunFullPipe(t *testing.T) {
 		Builds: []config.Build{
 			{
 				ID:      "build1",
-				Lang:    "fake",
+				Builder: "fake",
 				Binary:  "testing",
 				Flags:   []string{"-v"},
 				Ldflags: []string{"-X main.test=testing"},
@@ -133,7 +132,7 @@ func TestRunFullPipe(t *testing.T) {
 						{Cmd: "touch " + post},
 					},
 				},
-				Targets: []string{"whatever"},
+				Targets: []string{"linux_amd64"},
 			},
 		},
 		Dist: folder,
@@ -147,7 +146,7 @@ func TestRunFullPipe(t *testing.T) {
 	}})
 	require.FileExists(t, post)
 	require.FileExists(t, pre)
-	require.FileExists(t, filepath.Join(folder, "build1_whatever", "testing"))
+	require.FileExists(t, filepath.Join(folder, "build1_linux_amd64", "testing"))
 }
 
 func TestRunFullPipeFail(t *testing.T) {
@@ -158,7 +157,7 @@ func TestRunFullPipeFail(t *testing.T) {
 		Dist: folder,
 		Builds: []config.Build{
 			{
-				Lang:    "fakeFail",
+				Builder: "fakeFail",
 				Binary:  "testing",
 				Flags:   []string{"-v"},
 				Ldflags: []string{"-X main.test=testing"},
@@ -170,7 +169,7 @@ func TestRunFullPipeFail(t *testing.T) {
 						{Cmd: "touch " + post},
 					},
 				},
-				Targets: []string{"whatever"},
+				Targets: []string{"linux_amd64"},
 			},
 		},
 	}
@@ -187,10 +186,10 @@ func TestRunPipeFailingHooks(t *testing.T) {
 		Dist: folder,
 		Builds: []config.Build{
 			{
-				Lang:    "fake",
+				Builder: "fake",
 				Binary:  "hooks",
 				Hooks:   config.HookConfig{},
-				Targets: []string{"whatever"},
+				Targets: []string{"linux_amd64"},
 			},
 		},
 	}
@@ -223,7 +222,7 @@ func TestDefaultFail(t *testing.T) {
 		Dist: folder,
 		Builds: []config.Build{
 			{
-				Lang: "fakeFailDefault",
+				Builder: "fakeFailDefault",
 			},
 		},
 	}
@@ -387,7 +386,7 @@ func TestDefaultFailSingleBuild(t *testing.T) {
 	config := config.Project{
 		Dist: folder,
 		SingleBuild: config.Build{
-			Lang: "fakeFailDefault",
+			Builder: "fakeFailDefault",
 		},
 	}
 	ctx := context.New(config)
@@ -450,197 +449,13 @@ func TestTemplate(t *testing.T) {
 	require.Contains(t, binary, `-X "main.foo=123"`)
 }
 
-func TestRunHookEnvs(t *testing.T) {
-	tmp := testlib.Mktmp(t)
-
-	build := config.Build{
-		Env: []string{
-			fmt.Sprintf("FOO=%s/foo", tmp),
-			fmt.Sprintf("BAR=%s/bar", tmp),
-		},
-	}
-
-	opts := api.Options{
-		Name:   "binary-name",
-		Path:   "./binary-name",
-		Target: "darwin_amd64",
-	}
-
-	simpleHook := func(cmd string) config.BuildHooks {
-		return []config.BuildHook{{Cmd: cmd}}
-	}
-
-	t.Run("valid cmd template with ctx env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-			Env: []string{
-				fmt.Sprintf("CTXFOO=%s/foo", tmp),
-			},
-		}), opts, []string{}, simpleHook("touch {{ .Env.CTXFOO }}"))
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "foo"))
-	})
-
-	t.Run("valid cmd template with build env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, build.Env, simpleHook("touch {{ .Env.FOO }}"))
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "foo"))
-	})
-
-	t.Run("valid cmd template with hook env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, []string{}, []config.BuildHook{{
-			Cmd: "touch {{ .Env.HOOK_ONLY_FOO }}",
-			Env: []string{
-				fmt.Sprintf("HOOK_ONLY_FOO=%s/hook_only", tmp),
-			},
-		}})
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "hook_only"))
-	})
-
-	t.Run("valid cmd template with ctx and build env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-			Env: []string{
-				fmt.Sprintf("OVER_FOO=%s/ctx_over_build", tmp),
-			},
-		}), opts, []string{
-			fmt.Sprintf("OVER_FOO=%s/build_over_ctx", tmp),
-		}, simpleHook("touch {{ .Env.OVER_FOO }}"))
-		require.NoError(t, err)
-
-		require.FileExists(t, filepath.Join(tmp, "build_over_ctx"))
-		require.NoFileExists(t, filepath.Join(tmp, "ctx_over_build"))
-	})
-
-	t.Run("valid cmd template with ctx and hook env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-			Env: []string{
-				fmt.Sprintf("CTX_OR_HOOK_FOO=%s/ctx_over_hook", tmp),
-			},
-		}), opts, []string{}, []config.BuildHook{{
-			Cmd: "touch {{ .Env.CTX_OR_HOOK_FOO }}",
-			Env: []string{
-				fmt.Sprintf("CTX_OR_HOOK_FOO=%s/hook_over_ctx", tmp),
-			},
-		}})
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "hook_over_ctx"))
-		require.NoFileExists(t, filepath.Join(tmp, "ctx_over_hook"))
-	})
-
-	t.Run("valid cmd template with build and hook env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, []string{
-			fmt.Sprintf("BUILD_OR_HOOK_FOO=%s/build_over_hook", tmp),
-		}, []config.BuildHook{{
-			Cmd: "touch {{ .Env.BUILD_OR_HOOK_FOO }}",
-			Env: []string{
-				fmt.Sprintf("BUILD_OR_HOOK_FOO=%s/hook_over_build", tmp),
-			},
-		}})
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "hook_over_build"))
-		require.NoFileExists(t, filepath.Join(tmp, "build_over_hook"))
-	})
-
-	t.Run("valid cmd template with ctx, build and hook env", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-			Env: []string{
-				fmt.Sprintf("CTX_OR_BUILD_OR_HOOK_FOO=%s/ctx_wins", tmp),
-			},
-		}), opts, []string{
-			fmt.Sprintf("CTX_OR_BUILD_OR_HOOK_FOO=%s/build_wins", tmp),
-		}, []config.BuildHook{{
-			Cmd: "touch {{ .Env.CTX_OR_BUILD_OR_HOOK_FOO }}",
-			Env: []string{
-				fmt.Sprintf("CTX_OR_BUILD_OR_HOOK_FOO=%s/hook_wins", tmp),
-			},
-		}})
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "hook_wins"))
-		require.NoFileExists(t, filepath.Join(tmp, "ctx_wins"))
-		require.NoFileExists(t, filepath.Join(tmp, "build_wins"))
-	})
-
-	t.Run("invalid cmd template", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, build.Env, simpleHook("touch {{ .Env.FOOss }}"))
-		require.EqualError(t, err, `template: tmpl:1:13: executing "tmpl" at <.Env.FOOss>: map has no entry for key "FOOss"`)
-	})
-
-	t.Run("invalid dir template", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, build.Env, []config.BuildHook{{
-			Cmd: "echo something",
-			Dir: "{{ .Env.INVALID_ENV }}",
-		}})
-		require.EqualError(t, err, `template: tmpl:1:7: executing "tmpl" at <.Env.INVALID_ENV>: map has no entry for key "INVALID_ENV"`)
-	})
-
-	t.Run("invalid hook env template", func(t *testing.T) {
-		err := runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, build.Env, []config.BuildHook{{
-			Cmd: "echo something",
-			Env: []string{
-				"TEST={{ .Env.MISSING_ENV }}",
-			},
-		}})
-		require.EqualError(t, err, `template: tmpl:1:12: executing "tmpl" at <.Env.MISSING_ENV>: map has no entry for key "MISSING_ENV"`)
-	})
-
-	t.Run("build env inside shell", func(t *testing.T) {
-		shell := `#!/bin/sh -e
-touch "$BAR"`
-		err := os.WriteFile(filepath.Join(tmp, "test.sh"), []byte(shell), 0o750)
-		require.NoError(t, err)
-		err = runHook(context.New(config.Project{
-			Builds: []config.Build{
-				build,
-			},
-		}), opts, build.Env, simpleHook("sh test.sh"))
-		require.NoError(t, err)
-		require.FileExists(t, filepath.Join(tmp, "bar"))
-	})
-}
-
 func TestBuild_hooksKnowGoosGoarch(t *testing.T) {
 	tmpDir := testlib.Mktmp(t)
 	build := config.Build{
-		Lang:   "fake",
-		Goarch: []string{"amd64"},
-		Goos:   []string{"linux"},
-		Binary: "testing-goos-goarch.v{{.Version}}",
+		Builder: "fake",
+		Goarch:  []string{"amd64"},
+		Goos:    []string{"linux"},
+		Binary:  "testing-goos-goarch.v{{.Version}}",
 		Targets: []string{
 			"linux_amd64",
 		},
@@ -669,8 +484,8 @@ func TestPipeOnBuild_hooksRunPerTarget(t *testing.T) {
 	tmpDir := testlib.Mktmp(t)
 
 	build := config.Build{
-		Lang:   "fake",
-		Binary: "testing.v{{.Version}}",
+		Builder: "fake",
+		Binary:  "testing.v{{.Version}}",
 		Targets: []string{
 			"linux_amd64",
 			"darwin_amd64",
@@ -702,8 +517,8 @@ func TestPipeOnBuild_hooksRunPerTarget(t *testing.T) {
 
 func TestPipeOnBuild_invalidBinaryTpl(t *testing.T) {
 	build := config.Build{
-		Lang:   "fake",
-		Binary: "testing.v{{.XYZ}}",
+		Builder: "fake",
+		Binary:  "testing.v{{.XYZ}}",
 		Targets: []string{
 			"linux_amd64",
 		},
@@ -739,8 +554,8 @@ func TestBuildOptionsForTarget(t *testing.T) {
 				Name:   "testbinary",
 				Path:   filepath.Join(tmpDir, "testid_linux_amd64", "testbinary"),
 				Target: "linux_amd64",
-				Os:     "linux",
-				Arch:   "amd64",
+				Goos:   "linux",
+				Goarch: "amd64",
 			},
 		},
 		{
@@ -756,8 +571,8 @@ func TestBuildOptionsForTarget(t *testing.T) {
 				Name:   "testbinary_linux_amd64",
 				Path:   filepath.Join(tmpDir, "testid_linux_amd64", "testbinary_linux_amd64"),
 				Target: "linux_amd64",
-				Os:     "linux",
-				Arch:   "amd64",
+				Goos:   "linux",
+				Goarch: "amd64",
 			},
 		},
 		{
@@ -774,8 +589,44 @@ func TestBuildOptionsForTarget(t *testing.T) {
 				Name:   "distpath/linux/amd64/testbinary_linux_amd64",
 				Path:   filepath.Join(tmpDir, "distpath", "linux", "amd64", "testbinary_linux_amd64"),
 				Target: "linux_amd64",
-				Os:     "linux",
-				Arch:   "amd64",
+				Goos:   "linux",
+				Goarch: "amd64",
+			},
+		},
+		{
+			name: "with goarm",
+			build: config.Build{
+				ID:     "testid",
+				Binary: "testbinary",
+				Targets: []string{
+					"linux_arm_6",
+				},
+			},
+			expectedOpts: &api.Options{
+				Name:   "testbinary",
+				Path:   filepath.Join(tmpDir, "testid_linux_arm_6", "testbinary"),
+				Target: "linux_arm_6",
+				Goos:   "linux",
+				Goarch: "arm",
+				Goarm:  "6",
+			},
+		},
+		{
+			name: "with gomips",
+			build: config.Build{
+				ID:     "testid",
+				Binary: "testbinary",
+				Targets: []string{
+					"linux_mips_softfloat",
+				},
+			},
+			expectedOpts: &api.Options{
+				Name:   "testbinary",
+				Path:   filepath.Join(tmpDir, "testid_linux_mips_softfloat", "testbinary"),
+				Target: "linux_mips_softfloat",
+				Goos:   "linux",
+				Goarch: "mips",
+				Gomips: "softfloat",
 			},
 		},
 	}
@@ -798,45 +649,21 @@ func TestBuildOptionsForTarget(t *testing.T) {
 	}
 }
 
-func TestHookComplex(t *testing.T) {
-	tmp := testlib.Mktmp(t)
-
-	require.NoError(t, runHook(context.New(config.Project{}), api.Options{}, []string{}, config.BuildHooks{
-		{
-			Cmd: `bash -c "touch foo"`,
-		},
-		{
-			Cmd: `bash -c "touch \"bar\""`,
-		},
-	}))
-
-	require.FileExists(t, filepath.Join(tmp, "foo"))
-	require.FileExists(t, filepath.Join(tmp, "bar"))
-}
-
-func TestHookInvalidShelCommand(t *testing.T) {
-	require.Error(t, runHook(context.New(config.Project{}), api.Options{}, []string{}, config.BuildHooks{
-		{
-			Cmd: `bash -c "echo \"unterminated command\"`,
-		},
-	}))
-}
-
 func TestRunHookFailWithLogs(t *testing.T) {
 	folder := testlib.Mktmp(t)
 	config := config.Project{
 		Dist: folder,
 		Builds: []config.Build{
 			{
-				Lang:   "fakeFail",
-				Binary: "testing",
-				Flags:  []string{"-v"},
+				Builder: "fakeFail",
+				Binary:  "testing",
+				Flags:   []string{"-v"},
 				Hooks: config.HookConfig{
 					Pre: []config.BuildHook{
 						{Cmd: "sh -c 'echo foo; exit 1'"},
 					},
 				},
-				Targets: []string{"whatever"},
+				Targets: []string{"linux_amd64"},
 			},
 		},
 	}