From 5c136351940cdcacbc1705e82654346a38af36c9 Mon Sep 17 00:00:00 2001 From: Carlos A Becker Date: Fri, 22 Apr 2022 21:05:42 -0300 Subject: [PATCH] feat: first class build targets Adds the ability to tell goreleaser to use the first-class Go ports as targets. Closes #3053 Signed-off-by: Carlos A Becker --- internal/builders/golang/build.go | 48 +++++++++++++++++++++++--- internal/builders/golang/build_test.go | 36 +++++++++++++++++++ www/docs/customization/build.md | 27 +++++++++++---- 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/internal/builders/golang/build.go b/internal/builders/golang/build.go index bd6fd40d9c2..369fe87f777 100644 --- a/internal/builders/golang/build.go +++ b/internal/builders/golang/build.go @@ -65,29 +65,67 @@ func (*Builder) WithDefaults(build config.Build) (config.Build, error) { build.Goamd64 = []string{"v1"} } targets, err := buildtarget.List(build) - build.Targets = targets if err != nil { return build, err } + build.Targets = targets } else { - for i, target := range build.Targets { + targets := map[string]bool{} + for _, target := range build.Targets { + if target == go118FirstClassTargetsName || + target == goStableFirstClassTargetsName { + for _, t := range go118FirstClassTargets { + targets[t] = true + } + continue + } if strings.HasSuffix(target, "_amd64") { - build.Targets[i] = target + "_v1" + targets[target+"_v1"] = true + continue } if strings.HasSuffix(target, "_arm") { - build.Targets[i] = target + "_6" + targets[target+"_6"] = true + continue } if strings.HasSuffix(target, "_mips") || strings.HasSuffix(target, "_mips64") || strings.HasSuffix(target, "_mipsle") || strings.HasSuffix(target, "_mips64le") { - build.Targets[i] = target + "_hardfloat" + targets[target+"_hardfloat"] = true + continue } + targets[target] = true } + build.Targets = keys(targets) } return build, nil } +func keys(m map[string]bool) []string { + result := make([]string, 0, len(m)) + for k := range m { + result = append(result, k) + } + return result +} + +const ( + go118FirstClassTargetsName = "go_118_first_class" + goStableFirstClassTargetsName = "go_first_class" +) + +// go tool dist list -json | jq -r '.[] | select(.FirstClass) | [.GOOS, .GOARCH] | @tsv' +var go118FirstClassTargets = []string{ + "darwin_amd64_v1", + "darwin_arm64", + "linux_386", + "linux_amd64_v1", + "linux_arm_6", + "linux_arm64", + "windows_386", + "windows_amd64_v1", +} + // Build builds a golang build. func (*Builder) Build(ctx *context.Context, build config.Build, options api.Options) error { if err := checkMain(build); err != nil { diff --git a/internal/builders/golang/build_test.go b/internal/builders/golang/build_test.go index cf54b0d3239..b5940bca8ac 100644 --- a/internal/builders/golang/build_test.go +++ b/internal/builders/golang/build_test.go @@ -185,6 +185,42 @@ func TestWithDefaults(t *testing.T) { }, goBinary: "go", }, + "go first class targets": { + build: config.Build{ + ID: "foo3", + Binary: "foo", + Targets: []string{goStableFirstClassTargetsName}, + }, + targets: go118FirstClassTargets, + goBinary: "go", + }, + "go 1.18 first class targets": { + build: config.Build{ + ID: "foo3", + Binary: "foo", + Targets: []string{go118FirstClassTargetsName}, + }, + targets: go118FirstClassTargets, + goBinary: "go", + }, + "go 1.18 first class targets plus custom": { + build: config.Build{ + ID: "foo3", + Binary: "foo", + Targets: []string{"linux_amd64_v1", go118FirstClassTargetsName, "darwin_amd64_v2"}, + }, + targets: append(go118FirstClassTargets, "darwin_amd64_v2"), + goBinary: "go", + }, + "repeatin targets": { + build: config.Build{ + ID: "foo3", + Binary: "foo", + Targets: []string{go118FirstClassTargetsName, go118FirstClassTargetsName, goStableFirstClassTargetsName}, + }, + targets: go118FirstClassTargets, + goBinary: "go", + }, } { t.Run(name, func(t *testing.T) { if testcase.build.GoBinary != "" && testcase.build.GoBinary != "go" { diff --git a/www/docs/customization/build.md b/www/docs/customization/build.md index 128334ceeb9..b070055c33f 100644 --- a/www/docs/customization/build.md +++ b/www/docs/customization/build.md @@ -2,8 +2,8 @@ Builds can be customized in multiple ways. You can specify for which `GOOS`, `GOARCH` and `GOARM` binaries are built -(goreleaser will generate a matrix of all combinations), and you can change -the name of the binary, flags, environment variables, hooks and etc. +(GoReleaser will generate a matrix of all combinations), and you can change +the name of the binary, flags, environment variables, hooks and more. Here is a commented `builds` section with all fields specified: @@ -119,9 +119,16 @@ builds: # Optionally override the matrix generation and specify only the final list of targets. # Format is `{goos}_{goarch}` with optionally a suffix with `_{goarm}`, `_{goamd64}` or `_{gomips}`. + # + # Special values: + # - go_118_first_class: evaluates to the first-class targets of go1.18 + # - go_first_class: evaluates to latest stable go first-class targets, currently same as 1.18. + # # This overrides `goos`, `goarch`, `goarm`, `gomips`, `goamd64` and `ignores`. targets: - - linux_amd64 + - go_first_class + - go_118_first_class + - linux_amd64_v1 - darwin_arm64 - linux_arm_6 @@ -187,6 +194,13 @@ builds: !!! tip Learn more about the [name template engine](/customization/templates/). +!!! info + First-class build targets are gathered by running: + ```sh + go tool dist list -json | jq -r '.[] | select(.FirstClass) | [.GOOS, .GOARCH] | @tsv' + ``` + We also recommend reading the [official wiki about Go ports](https://github.com/golang/go/wiki/PortingPolicy#first-class-ports). + Here is an example with multiple binaries: ```yaml @@ -335,7 +349,7 @@ This is useful in scenarios where two tags point to the same commit. ## Reproducible Builds -To make your releases, checksums, and signatures reproducible, you will need to make some (if not all) of the following modifications to the build defaults in GoReleaser: +To make your releases, checksums and signatures reproducible, you will need to make some (if not all) of the following modifications to the build defaults in GoReleaser: * Modify `ldflags`: by default `main.Date` is set to the time GoReleaser is run (`{{.Date}}`), you can set this to `{{.CommitDate}}` or just not pass the variable. * Modify `mod_timestamp`: by default this is empty string, set to `{{.CommitTimestamp}}` or a constant value instead. @@ -407,5 +421,6 @@ There is no difference in how the binaries are handled. GoReleaser will fail. !!! warning - When using the `prebuilt` binary, there are no defaults for `goos` et al, - so you need to either provide those or the final `targets` matrix. + When using the `prebuilt` binary, there are no defaults for `goos`, + `goarch`, `goarm`, `gomips` and `goamd64`. + You'll need to either provide them or the final `targets` matrix.