diff --git a/internal/builders/golang/build.go b/internal/builders/golang/build.go index bd6fd40d9c2..da5e04a8b8e 100644 --- a/internal/builders/golang/build.go +++ b/internal/builders/golang/build.go @@ -39,6 +39,9 @@ func (*Builder) WithDefaults(build config.Build) (config.Build, error) { if build.GoBinary == "" { build.GoBinary = "go" } + if build.Command == "" { + build.Command = "build" + } if build.Dir == "" { build.Dir = "." } @@ -177,7 +180,7 @@ func withOverrides(ctx *context.Context, build config.Build, options api.Options } func buildGoBuildLine(ctx *context.Context, build config.Build, options api.Options, artifact *artifact.Artifact, env []string) ([]string, error) { - cmd := []string{build.GoBinary, "build"} + cmd := []string{build.GoBinary, build.Command} details, err := withOverrides(ctx, build, options) if err != nil { @@ -255,6 +258,9 @@ func run(ctx *context.Context, command, env []string, dir string) error { } func checkMain(build config.Build) error { + if build.NoMainCheck { + return nil + } main := build.Main if build.UnproxiedMain != "" { main = build.UnproxiedMain diff --git a/internal/builders/golang/build_test.go b/internal/builders/golang/build_test.go index cf54b0d3239..dac01ac152e 100644 --- a/internal/builders/golang/build_test.go +++ b/internal/builders/golang/build_test.go @@ -205,6 +205,21 @@ func TestWithDefaults(t *testing.T) { } } +func TestDefaults(t *testing.T) { + t.Run("command not set", func(t *testing.T) { + build, err := Default.WithDefaults(config.Build{}) + require.NoError(t, err) + require.Equal(t, "build", build.Command) + }) + t.Run("command set", func(t *testing.T) { + build, err := Default.WithDefaults(config.Build{ + Command: "test", + }) + require.NoError(t, err) + require.Equal(t, "test", build.Command) + }) +} + // createFakeGoBinaryWithVersion creates a temporary executable with the // given name, which will output a go version string with the given version. // The temporary directory created by this function will be placed in the PATH @@ -301,6 +316,7 @@ func TestBuild(t *testing.T) { "linux_mips64le_softfloat", }, GoBinary: "go", + Command: "build", BuildDetails: config.BuildDetails{ Asmflags: []string{".=", "all="}, Gcflags: []string{"all="}, @@ -479,6 +495,7 @@ func TestBuildCodeInSubdir(t *testing.T) { runtimeTarget, }, GoBinary: "go", + Command: "build", }, }, } @@ -506,6 +523,7 @@ func TestBuildWithDotGoDir(t *testing.T) { Binary: "foo", Targets: []string{runtimeTarget}, GoBinary: "go", + Command: "build", }, }, } @@ -534,6 +552,7 @@ func TestBuildFailed(t *testing.T) { runtimeTarget, }, GoBinary: "go", + Command: "build", }, }, } @@ -648,15 +667,7 @@ func TestRunPipeWithoutMainFunc(t *testing.T) { folder := testlib.Mktmp(t) writeMainWithoutMainFunc(t, folder) config := config.Project{ - Builds: []config.Build{ - { - Binary: "no-main", - Hooks: config.BuildHookConfig{}, - Targets: []string{ - runtimeTarget, - }, - }, - }, + Builds: []config.Build{{Binary: "no-main"}}, } ctx := context.New(config) ctx.Git.CurrentTag = "5.6.7" @@ -703,6 +714,28 @@ func TestRunPipeWithoutMainFunc(t *testing.T) { }) } +func TestBuildTests(t *testing.T) { + folder := testlib.Mktmp(t) + writeTest(t, folder) + config := config.Project{ + Builds: []config.Build{{ + Binary: "foo.test", + Command: "test", + BuildDetails: config.BuildDetails{ + Flags: []string{"-c"}, + }, + }}, + } + ctx := context.New(config) + ctx.Git.CurrentTag = "5.6.7" + ctx.Config.Builds[0].NoMainCheck = true + build, err := Default.WithDefaults(config.Builds[0]) + require.NoError(t, err) + require.NoError(t, Default.Build(ctx, build, api.Options{ + Target: runtimeTarget, + })) +} + func TestRunPipeWithProxiedRepo(t *testing.T) { folder := testlib.Mktmp(t) out, err := exec.Command("git", "clone", "https://github.com/goreleaser/goreleaser", "-b", "v0.161.1", "--depth=1", ".").CombinedOutput() @@ -744,6 +777,7 @@ import _ "github.com/goreleaser/goreleaser" runtimeTarget, }, GoBinary: "go", + Command: "build", }, }, } @@ -771,6 +805,7 @@ func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) { runtimeTarget, }, GoBinary: "go", + Command: "build", }, }, } @@ -925,6 +960,7 @@ func TestBuildModTimestamp(t *testing.T) { }, ModTimestamp: fmt.Sprintf("%d", modTime.Unix()), GoBinary: "go", + Command: "build", }, }, } @@ -977,7 +1013,7 @@ func TestBuildGoBuildLine(t *testing.T) { ctx.Git.Commit = "aaa" line, err := buildGoBuildLine(ctx, config.Builds[0], api.Options{ - Path: "foo", + Path: config.Builds[0].Binary, Goos: "linux", Goarch: "amd64", }, &artifact.Artifact{}, []string{}) @@ -995,7 +1031,9 @@ func TestBuildGoBuildLine(t *testing.T) { Tags: []string{"tag1", "tag2"}, Ldflags: []string{"ldflag1", "ldflag2"}, }, + Binary: "foo", GoBinary: "go", + Command: "build", }, []string{ "go", "build", "-flag1", "-flag2", @@ -1031,6 +1069,8 @@ func TestBuildGoBuildLine(t *testing.T) { }, }, GoBinary: "go", + Binary: "foo", + Command: "build", }, []string{ "go", "build", "-flag3", @@ -1046,9 +1086,23 @@ func TestBuildGoBuildLine(t *testing.T) { requireEqualCmd(t, config.Build{ Main: ".", GoBinary: "go", + Command: "build", + Binary: "foo", }, strings.Fields("go build -o foo .")) }) + t.Run("test", func(t *testing.T) { + requireEqualCmd(t, config.Build{ + Main: ".", + GoBinary: "go", + Command: "test", + Binary: "foo.test", + BuildDetails: config.BuildDetails{ + Flags: []string{"-c"}, + }, + }, strings.Fields("go test -c -o foo.test .")) + }) + t.Run("ldflags1", func(t *testing.T) { requireEqualCmd(t, config.Build{ Main: ".", @@ -1056,6 +1110,8 @@ func TestBuildGoBuildLine(t *testing.T) { Ldflags: []string{"-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.builtBy=goreleaser"}, }, GoBinary: "go", + Command: "build", + Binary: "foo", }, []string{ "go", "build", "-ldflags=-s -w -X main.version=1.2.3 -X main.commit=aaa -X main.builtBy=goreleaser", @@ -1070,6 +1126,8 @@ func TestBuildGoBuildLine(t *testing.T) { Ldflags: []string{"-s -w", "-X main.version={{.Version}}"}, }, GoBinary: "go", + Binary: "foo", + Command: "build", }, []string{"go", "build", "-ldflags=-s -w -X main.version=1.2.3", "-o", "foo", "."}) }) } @@ -1260,6 +1318,20 @@ func writeGoodMain(t *testing.T, folder string) { )) } +func writeTest(t *testing.T, folder string) { + t.Helper() + require.NoError(t, os.WriteFile( + filepath.Join(folder, "main_test.go"), + []byte("package main\nimport\"testing\"\nfunc TestFoo(t *testing.T) {t.Log(\"OK\")}"), + 0o644, + )) + require.NoError(t, os.WriteFile( + filepath.Join(folder, "go.mod"), + []byte("module foo\n"), + 0o666, + )) +} + func assertContainsError(t *testing.T, err error, s string) { t.Helper() require.Error(t, err) diff --git a/pkg/config/config.go b/pkg/config/config.go index f8e38f86d10..f3720dce37e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -312,7 +312,9 @@ type Build struct { ModTimestamp string `yaml:"mod_timestamp,omitempty"` Skip bool `yaml:"skip,omitempty"` GoBinary string `yaml:"gobinary,omitempty"` + Command string `yaml:"command,omitempty"` NoUniqueDistDir bool `yaml:"no_unique_dist_dir,omitempty"` + NoMainCheck bool `yaml:"no_main_check,omitempty"` UnproxiedMain string `yaml:"-"` // used by gomod.proxy UnproxiedDir string `yaml:"-"` // used by gomod.proxy diff --git a/www/docs/customization/build.md b/www/docs/customization/build.md index 128334ceeb9..c2c8ca08dca 100644 --- a/www/docs/customization/build.md +++ b/www/docs/customization/build.md @@ -125,11 +125,20 @@ builds: - darwin_arm64 - linux_arm_6 - # Set a specific go binary to use when building. It is safe to ignore - # this option in most cases. + # Set a specific go binary to use when building. + # It is safe to ignore this option in most cases. + # # Default is "go" gobinary: "go1.13.4" + # Sets the command to run to build. + # Can be useful if you want to build tests, for example, + # in which case you can set this to "test". + # It is safe to ignore this option in most cases. + # + # Default is "build". + command: test + # Set the modified timestamp on the output binary, typically # you would do this to ensure a build was reproducible. Pass # empty string to skip modifying the output. @@ -158,6 +167,12 @@ builds: # Defaults to `false`. no_unique_dist_dir: true + # By default, GoReleaser will check if the main filepath has a main function. + # This can be used to skip that check, in case you're building tests, for example. + # + # Defaults to `false`. + no_main_check: true + # Builder allows you to use a different build implementation. # This is a GoReleaser Pro feature. # Valid options are: `go` and `prebuilt`.