1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-11 14:39:28 +02:00

feat: allow a --output flag on goreleaser build (#2701)

* feat: allow a --output flag on goreleaser build

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: single build always to copies to root

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>
This commit is contained in:
Carlos Alexandro Becker 2022-02-05 18:19:12 -03:00 committed by GitHub
parent 750d520638
commit c42a2fdc76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 109 additions and 1 deletions

View File

@ -3,12 +3,15 @@ package cmd
import (
"fmt"
"os"
"path/filepath"
"runtime"
"time"
"github.com/apex/log"
"github.com/caarlos0/ctrlc"
"github.com/fatih/color"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/gio"
"github.com/goreleaser/goreleaser/internal/middleware/errhandler"
"github.com/goreleaser/goreleaser/internal/middleware/logging"
"github.com/goreleaser/goreleaser/internal/middleware/skip"
@ -34,6 +37,7 @@ type buildOpts struct {
parallelism int
timeout time.Duration
singleTarget bool
output string
}
func newBuildCmd() *buildCmd {
@ -90,6 +94,7 @@ defaulting to the current's machine target if not set.
cmd.Flags().BoolVar(&root.opts.singleTarget, "single-target", false, "Builds only for current GOOS and GOARCH")
cmd.Flags().StringVar(&root.opts.id, "id", "", "Builds only the specified build id")
cmd.Flags().BoolVar(&root.opts.deprecated, "deprecated", false, "Force print the deprecation message - tests only")
cmd.Flags().StringVarP(&root.opts.output, "output", "o", "", "Path to the binary, defaults to the distribution folder according to configs. Only taked into account when using --single-target and a single id (either with --id or if config only has one build)")
_ = cmd.Flags().MarkHidden("deprecated")
root.cmd = cmd
@ -107,7 +112,7 @@ func buildProject(options buildOpts) (*context.Context, error) {
return nil, err
}
return ctx, ctrlc.Default.Run(ctx, func() error {
for _, pipe := range pipeline.BuildCmdPipeline {
for _, pipe := range setupPipeline(ctx, options) {
if err := skip.Maybe(
pipe,
logging.Log(
@ -123,6 +128,13 @@ func buildProject(options buildOpts) (*context.Context, error) {
})
}
func setupPipeline(ctx *context.Context, options buildOpts) []pipeline.Piper {
if options.singleTarget && (options.id != "" || len(ctx.Config.Builds) == 1) {
return append(pipeline.BuildCmdPipeline, withOutputPipe{options.output})
}
return pipeline.BuildCmdPipeline
}
func setupBuildContext(ctx *context.Context, options buildOpts) error {
ctx.Parallelism = runtime.NumCPU()
if options.parallelism > 0 {
@ -191,3 +203,21 @@ func setupBuildID(ctx *context.Context, id string) error {
ctx.Config.Builds = keep
return nil
}
// withOutputPipe copies the binary from dist to the specified output path.
type withOutputPipe struct {
output string
}
func (w withOutputPipe) String() string {
return fmt.Sprintf("copying binary to %q", w.output)
}
func (w withOutputPipe) Run(ctx *context.Context) error {
path := ctx.Artifacts.Filter(artifact.ByType(artifact.Binary)).List()[0].Path
out := w.output
if out == "" {
out = filepath.Base(path)
}
return gio.Copy(path, out)
}

View File

@ -5,6 +5,7 @@ import (
"runtime"
"testing"
"github.com/goreleaser/goreleaser/internal/pipeline"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
"github.com/stretchr/testify/require"
@ -40,6 +41,83 @@ func TestBuildBrokenProject(t *testing.T) {
require.EqualError(t, cmd.cmd.Execute(), "failed to parse dir: .: main.go:1:1: expected 'package', found not")
}
func TestSetupPipeline(t *testing.T) {
t.Run("regular", func(t *testing.T) {
require.Equal(
t,
pipeline.BuildCmdPipeline,
setupPipeline(context.New(config.Project{}), buildOpts{}),
)
})
t.Run("single-target", func(t *testing.T) {
require.Equal(
t,
pipeline.BuildCmdPipeline,
setupPipeline(context.New(config.Project{}), buildOpts{
singleTarget: true,
}),
)
})
t.Run("single-target and id", func(t *testing.T) {
require.Equal(
t,
append(pipeline.BuildCmdPipeline, withOutputPipe{""}),
setupPipeline(context.New(config.Project{}), buildOpts{
singleTarget: true,
id: "foo",
}),
)
})
t.Run("single-target and single build on config", func(t *testing.T) {
require.Equal(
t,
append(pipeline.BuildCmdPipeline, withOutputPipe{""}),
setupPipeline(
context.New(config.Project{
Builds: []config.Build{{}},
}),
buildOpts{
singleTarget: true,
},
),
)
})
t.Run("single-target, id and output", func(t *testing.T) {
require.Equal(
t,
append(pipeline.BuildCmdPipeline, withOutputPipe{"foobar"}),
setupPipeline(
context.New(config.Project{}),
buildOpts{
singleTarget: true,
id: "foo",
output: "foobar",
},
),
)
})
t.Run("single-target, single build on config and output", func(t *testing.T) {
require.Equal(
t,
append(pipeline.BuildCmdPipeline, withOutputPipe{"zaz"}),
setupPipeline(
context.New(config.Project{
Builds: []config.Build{{}},
}),
buildOpts{
singleTarget: true,
output: "zaz",
},
),
)
})
}
func TestBuildFlags(t *testing.T) {
setup := func(opts buildOpts) *context.Context {
ctx := context.New(config.Project{})