Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: validate goos, goarch, goarm and gomips #1886

Merged
merged 3 commits into from Nov 5, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 7 additions & 3 deletions internal/builders/golang/build.go
Expand Up @@ -34,7 +34,7 @@ func init() {
type Builder struct{}

// WithDefaults sets the defaults for a golang build and returns it.
func (*Builder) WithDefaults(build config.Build) config.Build {
func (*Builder) WithDefaults(build config.Build) (config.Build, error) {
if build.Dir == "" {
build.Dir = "."
}
Expand All @@ -54,12 +54,16 @@ func (*Builder) WithDefaults(build config.Build) config.Build {
if len(build.Goarm) == 0 {
build.Goarm = []string{"6"}
}
build.Targets = matrix(build)
targets, err := matrix(build)
build.Targets = targets
if err != nil {
return build, err
}
}
if build.GoBinary == "" {
build.GoBinary = "go"
}
return build
return build, nil
}

// Build builds a golang build.
Expand Down
49 changes: 48 additions & 1 deletion internal/builders/golang/build_test.go
Expand Up @@ -94,13 +94,60 @@ func TestWithDefaults(t *testing.T) {
}
var ctx = context.New(config)
ctx.Git.CurrentTag = "5.6.7"
var build = Default.WithDefaults(ctx.Config.Builds[0])
build, err := Default.WithDefaults(ctx.Config.Builds[0])
require.NoError(t, err)
require.ElementsMatch(t, build.Targets, testcase.targets)
require.EqualValues(t, testcase.goBinary, build.GoBinary)
})
}
}

func TestInvalidTargets(t *testing.T) {
type testcase struct {
build config.Build
expectedErr string
}
for s, tc := range map[string]testcase{
"goos": {
build: config.Build{
Goos: []string{"darwin", "darwim"},
},
expectedErr: "invalid goos: darwim",
},
"goarch": {
build: config.Build{
Goarch: []string{"amd64", "i386", "386"},
},
expectedErr: "invalid goarch: i386",
},
"goarm": {
build: config.Build{
Goarch: []string{"arm"},
Goarm: []string{"6", "9", "8", "7"},
},
expectedErr: "invalid goarm: 9",
},
"gomips": {
build: config.Build{
Goarch: []string{"mips"},
Gomips: []string{"softfloat", "mehfloat", "hardfloat"},
},
expectedErr: "invalid gomips: mehfloat",
},
} {
t.Run(s, func(t *testing.T) {
var config = config.Project{
Builds: []config.Build{
tc.build,
},
}
var ctx = context.New(config)
_, err := Default.WithDefaults(ctx.Config.Builds[0])
require.EqualError(t, err, tc.expectedErr)
})
}
}

func TestBuild(t *testing.T) {
folder, back := testlib.Mktmp(t)
defer back()
Expand Down
149 changes: 101 additions & 48 deletions internal/builders/golang/targets.go
Expand Up @@ -22,10 +22,24 @@ func (t target) String() string {
return fmt.Sprintf("%s_%s", t.os, t.arch)
}

func matrix(build config.Build) (result []string) {
func matrix(build config.Build) ([]string, error) {
// nolint:prealloc
var targets []target
// nolint:prealloc
var result []string
for _, target := range allBuildTargets(build) {
if !contains(target.os, validGoos) {
return result, fmt.Errorf("invalid goos: %s", target.os)
}
if !contains(target.arch, validGoarch) {
return result, fmt.Errorf("invalid goarch: %s", target.arch)
}
if target.arm != "" && !contains(target.arm, validGoarm) {
return result, fmt.Errorf("invalid goarm: %s", target.arm)
}
if target.mips != "" && !contains(target.mips, validGomips) {
return result, fmt.Errorf("invalid gomips: %s", target.mips)
}
if !valid(target) {
log.WithField("target", target).
Debug("skipped invalid build")
Expand All @@ -41,7 +55,7 @@ func matrix(build config.Build) (result []string) {
for _, target := range targets {
result = append(result, target.String())
}
return
return result, nil
}

func allBuildTargets(build config.Build) (targets []target) {
Expand Down Expand Up @@ -98,56 +112,95 @@ func ignored(build config.Build, target target) bool {
}

func valid(target target) bool {
var s = target.os + target.arch
for _, a := range validTargets {
if a == s {
return contains(target.os+target.arch, validTargets)
}

func contains(s string, ss []string) bool {
for _, z := range ss {
if z == s {
return true
}
}
return false
}

// list from https://golang.org/doc/install/source#environment
// lists from https://golang.org/doc/install/source#environment
// nolint: gochecknoglobals
var validTargets = []string{
"aixppc64",
"android386",
"androidamd64",
"androidarm",
"androidarm64",
// "darwin386", - deprecated on latest go 1.15+
"darwinamd64",
// "darwinarm", - requires admin rights and other ios stuff
// "darwinarm64", - requires admin rights and other ios stuff
"dragonflyamd64",
"freebsd386",
"freebsdamd64",
"freebsdarm",
"freebsdarm64", // not on the official list for some reason, yet its supported on go 1.14+
"illumosamd64",
"jswasm",
"linux386",
"linuxamd64",
"linuxarm",
"linuxarm64",
"linuxppc64",
"linuxppc64le",
"linuxmips",
"linuxmipsle",
"linuxmips64",
"linuxmips64le",
"linuxs390x",
"netbsd386",
"netbsdamd64",
"netbsdarm",
"openbsd386",
"openbsdamd64",
"openbsdarm",
"openbsdarm64",
"plan9386",
"plan9amd64",
"plan9arm",
"solarisamd64",
"windows386",
"windowsamd64",
}
var (
validTargets = []string{
"aixppc64",
"android386",
"androidamd64",
"androidarm",
"androidarm64",
// "darwin386", - deprecated on latest go 1.15+
"darwinamd64",
// "darwinarm", - requires admin rights and other ios stuff
// "darwinarm64", - requires admin rights and other ios stuff
"dragonflyamd64",
"freebsd386",
"freebsdamd64",
"freebsdarm",
"freebsdarm64", // not on the official list for some reason, yet its supported on go 1.14+
"illumosamd64",
"jswasm",
"linux386",
"linuxamd64",
"linuxarm",
"linuxarm64",
"linuxppc64",
"linuxppc64le",
"linuxmips",
"linuxmipsle",
"linuxmips64",
"linuxmips64le",
"linuxs390x",
"netbsd386",
"netbsdamd64",
"netbsdarm",
"openbsd386",
"openbsdamd64",
"openbsdarm",
"openbsdarm64",
"plan9386",
"plan9amd64",
"plan9arm",
"solarisamd64",
"windows386",
"windowsamd64",
}

validGoos = []string{
"aix",
"android",
"darwin",
"dragonfly",
"freebsd",
"illumos",
"js",
"linux",
"netbsd",
"openbsd",
"plan9",
"solaris",
"windows",
}

validGoarch = []string{
"386",
"amd64",
"arm",
"arm64",
"mips",
"mips64",
"mips64le",
"mipsle",
"ppc64",
"ppc64le",
"s390x",
"wasm",
}

validGoarm = []string{"5", "6", "7"}
validGomips = []string{"hardfloat", "softfloat"}
)
4 changes: 3 additions & 1 deletion internal/builders/golang/targets_test.go
Expand Up @@ -53,6 +53,8 @@ func TestAllBuildTargets(t *testing.T) {
},
},
}
result, err := matrix(build)
require.NoError(t, err)
require.Equal(t, []string{
"linux_386",
"linux_amd64",
Expand All @@ -74,7 +76,7 @@ func TestAllBuildTargets(t *testing.T) {
"openbsd_amd64",
"openbsd_arm64",
"js_wasm",
}, matrix(build))
}, result)
}

func TestGoosGoarchCombos(t *testing.T) {
Expand Down
14 changes: 10 additions & 4 deletions internal/pipe/build/build.go
Expand Up @@ -51,18 +51,24 @@ func (Pipe) Run(ctx *context.Context) error {
func (Pipe) Default(ctx *context.Context) error {
var ids = ids.New("builds")
for i, build := range ctx.Config.Builds {
ctx.Config.Builds[i] = buildWithDefaults(ctx, build)
build, err := buildWithDefaults(ctx, build)
if err != nil {
return err
}
ctx.Config.Builds[i] = build
ids.Inc(ctx.Config.Builds[i].ID)
}
if len(ctx.Config.Builds) == 0 {
ctx.Config.Builds = []config.Build{
buildWithDefaults(ctx, ctx.Config.SingleBuild),
build, err := buildWithDefaults(ctx, ctx.Config.SingleBuild)
if err != nil {
return err
}
ctx.Config.Builds = []config.Build{build}
}
return ids.Validate()
}

func buildWithDefaults(ctx *context.Context, build config.Build) config.Build {
func buildWithDefaults(ctx *context.Context, build config.Build) (config.Build, error) {
if build.Lang == "" {
build.Lang = "go"
}
Expand Down
48 changes: 43 additions & 5 deletions internal/pipe/build/build_test.go
Expand Up @@ -17,16 +17,21 @@ import (
"github.com/stretchr/testify/require"
)

var errFailedBuild = errors.New("fake builder failed")
var errFailedDefault = errors.New("fake builder defaults failed")

type fakeBuilder struct {
fail bool
fail bool
failDefault bool
}

func (*fakeBuilder) WithDefaults(build config.Build) config.Build {
return build
func (f *fakeBuilder) WithDefaults(build config.Build) (config.Build, error) {
if f.failDefault {
return build, errFailedDefault
}
return build, nil
}

var errFailedBuild = errors.New("fake builder failed")

func (f *fakeBuilder) Build(ctx *context.Context, build config.Build, options api.Options) error {
if f.fail {
return errFailedBuild
Expand All @@ -48,6 +53,9 @@ func init() {
api.Register("fakeFail", &fakeBuilder{
fail: true,
})
api.Register("fakeFailDefault", &fakeBuilder{
failDefault: true,
})
}

func TestPipeDescription(t *testing.T) {
Expand Down Expand Up @@ -212,6 +220,22 @@ func TestDefaultNoBuilds(t *testing.T) {
require.NoError(t, Pipe{}.Default(ctx))
}

func TestDefaultFail(t *testing.T) {
folder, back := testlib.Mktmp(t)
defer back()
var config = config.Project{
Dist: folder,
Builds: []config.Build{
{
Lang: "fakeFailDefault",
},
},
}
var ctx = context.New(config)
require.EqualError(t, Pipe{}.Default(ctx), errFailedDefault.Error())
require.Empty(t, ctx.Artifacts.List())
}

func TestDefaultExpandEnv(t *testing.T) {
require.NoError(t, os.Setenv("XBAR", "FOOBAR"))
var ctx = &context.Context{
Expand Down Expand Up @@ -351,6 +375,20 @@ func TestDefaultFillSingleBuild(t *testing.T) {
require.Equal(t, ctx.Config.Builds[0].Binary, "foo")
}

func TestDefaultFailSingleBuild(t *testing.T) {
folder, back := testlib.Mktmp(t)
defer back()
var config = config.Project{
Dist: folder,
SingleBuild: config.Build{
Lang: "fakeFailDefault",
},
}
var ctx = context.New(config)
require.EqualError(t, Pipe{}.Default(ctx), errFailedDefault.Error())
require.Empty(t, ctx.Artifacts.List())
}

func TestSkipBuild(t *testing.T) {
folder, back := testlib.Mktmp(t)
defer back()
Expand Down