Skip to content

Commit

Permalink
feat: Add goreleaser mage package (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
aweris authored Nov 17, 2022
1 parent 85c0bf5 commit 7617629
Show file tree
Hide file tree
Showing 8 changed files with 864 additions and 0 deletions.
2 changes: 2 additions & 0 deletions mage/goreleaser/build/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package build provides a simple interface to the goreleaser build.
package build
181 changes: 181 additions & 0 deletions mage/goreleaser/build/mage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package build

import (
"context"
"fmt"
"os"
"strconv"
"time"

"github.com/magefile/mage/mg"

"github.com/mesosphere/daggers/mage/goreleaser/cli"
)

const (
goreleaserConfigEnvVar = "GORELEASER_BUILD_CONFIG"
goreleaserIDEnvVar = "GORELEASER_BUILD_ID"
goreleaserOutputEnvVar = "GORELEASER_BUILD_OUTPUT"
goreleaserParallelismEnvVar = "GORELEASER_BUILD_PARALLELISM"
goreleaserRmDistEnvVar = "GORELEASER_BUILD_RM_DIST"
goreleaserSingleTargetEnvVar = "GORELEASER_BUILD_SINGLE_TARGET"
goreleaserSkipPostCommitHooksEnvVar = "GORELEASER_BUILD_SKIP_POST_COMMIT_HOOKS"
goreleaserSkipValidateEnvVar = "GORELEASER_BUILD_SKIP_VALIDATE"
goreleaserSnapshotEnvVar = "GORELEASER_BUILD_SNAPSHOT"
goreleaserTimeoutEnvVar = "GORELEASER_BUILD_TIMEOUT"
)

// Build runs goreleaser build with --rm-dist and --single-target flags.
func Build(_ context.Context) error {
result, err := BuildWithOptions(
WithRmDist(true),
WithSingleTarget(true),
)
if err != nil {
return err
}

fmt.Printf(
"Build is successful for project: %s and version: %s\n",
result.Metadata.ProjectName,
result.Metadata.Version,
)

return nil
}

// BuildSnapshot runs goreleaser build with --snapshot, --rm-dist and --single-target flags.
//
//nolint:revive // Disable stuttering check.
func BuildSnapshot(_ context.Context) error {
result, err := BuildWithOptions(
WithRmDist(true),
WithSingleTarget(true),
WithSnapshot(true),
)
if err != nil {
return err
}

fmt.Printf(
"Build snapshot is successful for project: %s and version: %s\n",
result.Metadata.ProjectName,
result.Metadata.Version,
)

return nil
}

// BuildWithOptions runs goreleaser build with specific options.
//
//nolint:revive // Disable stuttering check.
func BuildWithOptions(opts ...Option) (*cli.Result, error) {
debug := mg.Debug() || mg.Verbose()

envOpts, err := loadOptionsFromEnv()
if err != nil {
return nil, err
}

// Combine options from environment variables and options passed to this function. Environment variables
// take precedence to allow overriding from the arguments passed to this function.
var combinedOpts []Option

combinedOpts = append(combinedOpts, envOpts...)
combinedOpts = append(combinedOpts, opts...)

options := config{}
for _, opt := range combinedOpts {
options = opt(options)
}

return cli.Run(cli.CommandBuild, debug, options.env, options.toArgs())
}

func loadOptionsFromEnv() ([]Option, error) {
var opts []Option

opts = append(stringOptFromEnvVar(goreleaserConfigEnvVar, WithConfig), opts...)
opts = append(stringOptFromEnvVar(goreleaserIDEnvVar, WithID), opts...)
opts = append(stringOptFromEnvVar(goreleaserOutputEnvVar, WithOutput), opts...)
opts = append(stringOptFromEnvVar(goreleaserParallelismEnvVar, WithParallelism), opts...)

boolOpts, err := boolOptFromEnvVar(goreleaserRmDistEnvVar, WithRmDist)
if err != nil {
return nil, err
}
opts = append(boolOpts, opts...)

boolOpts, err = boolOptFromEnvVar(goreleaserSingleTargetEnvVar, WithSingleTarget)
if err != nil {
return nil, err
}
opts = append(boolOpts, opts...)

boolOpts, err = boolOptFromEnvVar(goreleaserSkipPostCommitHooksEnvVar, SkipPostCommitHooks)
if err != nil {
return nil, err
}
opts = append(boolOpts, opts...)

boolOpts, err = boolOptFromEnvVar(goreleaserSkipValidateEnvVar, SkipValidate)
if err != nil {
return nil, err
}
opts = append(boolOpts, opts...)

boolOpts, err = boolOptFromEnvVar(goreleaserSnapshotEnvVar, WithSnapshot)
if err != nil {
return nil, err
}
opts = append(boolOpts, opts...)

durationOpts, err := durationOptFromEnvVar(goreleaserTimeoutEnvVar, WithTimeout)
if err != nil {
return nil, err
}
opts = append(durationOpts, opts...)

return opts, nil
}

// stringOptFromEnvVar returns a slice containing a single option if the specified environment variable is set.
// This function returns a slice to make it easier to chain calls in optsFromEnvVars.
// Returns a nil slice if the env var is not set.
func stringOptFromEnvVar(envVarName string, optFn func(string) Option) []Option {
if envVarValue, ok := os.LookupEnv(envVarName); ok {
return []Option{optFn(envVarValue)}
}

return nil
}

// boolOptFromEnvVar returns a slice containing a single option if the specified environment variable is set.
// This function returns a slice to make it easier to chain calls in optsFromEnvVars.
// Returns a nil slice if the env var is not set.
func boolOptFromEnvVar(envVarName string, optFn func(bool) Option) ([]Option, error) {
if envVarValue, ok := os.LookupEnv(envVarName); ok {
boolVal, err := strconv.ParseBool(envVarValue)
if err != nil {
return nil, fmt.Errorf("failed to parse %q as a boolean: %w", envVarName, err)
}
return []Option{optFn(boolVal)}, nil
}

return nil, nil
}

// durationOptFromEnvVar returns a slice containing a single option if the specified environment variable is set.
// This function returns a slice to make it easier to chain calls in optsFromEnvVars.
// Returns a nil slice if the env var is not set.
func durationOptFromEnvVar(envVarName string, optFn func(duration time.Duration) Option) ([]Option, error) {
if envVarValue, ok := os.LookupEnv(envVarName); ok {
durationVal, err := time.ParseDuration(envVarValue)
if err != nil {
return nil, fmt.Errorf("failed to parse %q as a duration: %w", envVarName, err)
}
return []Option{optFn(durationVal)}, nil
}

return nil, nil
}
145 changes: 145 additions & 0 deletions mage/goreleaser/build/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package build

import (
"time"
)

type config struct {
env map[string]string
config string
id string
output string
parallelism string
rmDist bool
singleTarget bool
skipPostCommitHooks bool
skipValidate bool
snapshot bool
timeout string
}

// Option is a function that configures the goreleaser build options.
type Option func(config config) config

// WithEnv append extra env variables to goreleaser build process.
func WithEnv(env map[string]string) Option {
return func(config config) config {
config.env = env
return config
}
}

// WithConfig sets --config flag.
func WithConfig(configPath string) Option {
return func(config config) config {
config.config = configPath
return config
}
}

// WithID sets --id flag.
func WithID(id string) Option {
return func(config config) config {
config.id = id
return config
}
}

// WithOutput sets --output.
func WithOutput(output string) Option {
return func(config config) config {
config.output = output
return config
}
}

// WithParallelism sets --parallelism.
func WithParallelism(parallelism string) Option {
return func(config config) config {
config.parallelism = parallelism
return config
}
}

// WithRmDist sets --rm-dist.
func WithRmDist(rmDist bool) Option {
return func(config config) config {
config.rmDist = rmDist
return config
}
}

// WithSingleTarget sets --single-target.
func WithSingleTarget(singleTarget bool) Option {
return func(config config) config {
config.singleTarget = singleTarget
return config
}
}

// SkipPostCommitHooks sets--skip-post-hooks.
func SkipPostCommitHooks(skipPostCommitHooks bool) Option {
return func(config config) config {
config.skipPostCommitHooks = skipPostCommitHooks
return config
}
}

// SkipValidate sets --skip-validate.
func SkipValidate(skipValidate bool) Option {
return func(config config) config {
config.skipValidate = skipValidate
return config
}
}

// WithSnapshot sets --snapshot.
func WithSnapshot(snapshot bool) Option {
return func(config config) config {
config.snapshot = snapshot
return config
}
}

// WithTimeout sets --timeout duration.
func WithTimeout(timeout time.Duration) Option {
return func(config config) config {
config.timeout = timeout.String()
return config
}
}

func (c *config) toArgs() []string {
var args []string

args = appendNonEmptyStringVal(args, "--config", c.config)
args = appendNonEmptyStringVal(args, "--id", c.id)
args = appendNonEmptyStringVal(args, "--output", c.output)
args = appendNonEmptyStringVal(args, "--parallelism", c.parallelism)
args = appendBoolVal(args, "--rm-dist", c.rmDist)
args = appendBoolVal(args, "--single-target", c.singleTarget)
args = appendBoolVal(args, "--skip-post-hooks", c.skipPostCommitHooks)
args = appendBoolVal(args, "--skip-validate", c.skipValidate)
args = appendBoolVal(args, "--snapshot", c.snapshot)
args = appendNonEmptyStringVal(args, "--timeout", c.timeout)

return args
}

func appendNonEmptyStringVal(slice []string, flag, val string) []string {
// if val is empty return slice as it's
if val == "" {
return slice
}

return append(slice, flag, val)
}

func appendBoolVal(slice []string, flag string, val bool) []string {
// if val is false, no need to append the flag
if !val {
return slice
}

return append(slice, flag)
}
Loading

0 comments on commit 7617629

Please sign in to comment.