You've already forked goreleaser
							
							
				mirror of
				https://github.com/goreleaser/goreleaser.git
				synced 2025-10-30 23:58:09 +02:00 
			
		
		
		
	refactor: improve tmpls that eval to a bool (#3726)
- added a tmpl.Bool that checks if the result of a template is "true" - added an ErrSkipper interface so Skip() methods can return errors as well --------- Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							750664f449
						
					
				
				
					commit
					90a82157ca
				
			| @@ -16,12 +16,26 @@ type Skipper interface { | ||||
| 	fmt.Stringer | ||||
| } | ||||
|  | ||||
| // Skipper defines a method to skip an entire Piper. | ||||
| type ErrSkipper interface { | ||||
| 	// Skip returns true if the Piper should be skipped. | ||||
| 	Skip(ctx *context.Context) (bool, error) | ||||
| 	fmt.Stringer | ||||
| } | ||||
|  | ||||
| // Maybe returns an action that skips immediately if the given p is a Skipper | ||||
| // and its Skip method returns true. | ||||
| func Maybe(skipper interface{}, next middleware.Action) middleware.Action { | ||||
| 	if skipper, ok := skipper.(Skipper); ok { | ||||
| 		return Maybe(wrapper{skipper}, next) | ||||
| 	} | ||||
| 	if skipper, ok := skipper.(ErrSkipper); ok { | ||||
| 		return func(ctx *context.Context) error { | ||||
| 			if skipper.Skip(ctx) { | ||||
| 			skip, err := skipper.Skip(ctx) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("skip %s: %w", skipper.String(), err) | ||||
| 			} | ||||
| 			if skip { | ||||
| 				log.Debugf("skipped %s", skipper.String()) | ||||
| 				return nil | ||||
| 			} | ||||
| @@ -30,3 +44,19 @@ func Maybe(skipper interface{}, next middleware.Action) middleware.Action { | ||||
| 	} | ||||
| 	return next | ||||
| } | ||||
|  | ||||
| var _ ErrSkipper = wrapper{} | ||||
|  | ||||
| type wrapper struct { | ||||
| 	skipper Skipper | ||||
| } | ||||
|  | ||||
| // String implements SkipperErr | ||||
| func (w wrapper) String() string { | ||||
| 	return w.skipper.String() | ||||
| } | ||||
|  | ||||
| // Skip implements SkipperErr | ||||
| func (w wrapper) Skip(ctx *context.Context) (bool, error) { | ||||
| 	return w.skipper.Skip(ctx), nil | ||||
| } | ||||
|   | ||||
| @@ -27,6 +27,29 @@ func TestSkip(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestSkipErr(t *testing.T) { | ||||
| 	fakeErr := fmt.Errorf("fake error") | ||||
| 	action := func(_ *context.Context) error { | ||||
| 		return fakeErr | ||||
| 	} | ||||
|  | ||||
| 	t.Run("no err", func(t *testing.T) { | ||||
| 		require.NoError(t, Maybe(errSkipper{true, nil}, action)(nil)) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("with err", func(t *testing.T) { | ||||
| 		require.EqualError(t, Maybe( | ||||
| 			errSkipper{false, fmt.Errorf("skip err")}, | ||||
| 			action, | ||||
| 		)(nil), "skip blah: skip err") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	_ Skipper    = skipper{} | ||||
| 	_ ErrSkipper = errSkipper{} | ||||
| ) | ||||
|  | ||||
| type skipper struct { | ||||
| 	skip bool | ||||
| } | ||||
| @@ -36,3 +59,14 @@ func (s skipper) String() string { return "blah" } | ||||
| func (s skipper) Skip(_ *context.Context) bool { | ||||
| 	return s.skip | ||||
| } | ||||
|  | ||||
| type errSkipper struct { | ||||
| 	skip bool | ||||
| 	err  error | ||||
| } | ||||
|  | ||||
| func (s errSkipper) String() string { return "blah" } | ||||
|  | ||||
| func (s errSkipper) Skip(_ *context.Context) (bool, error) { | ||||
| 	return s.skip, s.err | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,6 @@ package announce | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/caarlos0/log" | ||||
| 	"github.com/goreleaser/goreleaser/internal/middleware/errhandler" | ||||
| 	"github.com/goreleaser/goreleaser/internal/middleware/logging" | ||||
| 	"github.com/goreleaser/goreleaser/internal/middleware/skip" | ||||
| @@ -50,20 +49,11 @@ type Pipe struct{} | ||||
|  | ||||
| func (Pipe) String() string { return "announcing" } | ||||
|  | ||||
| func (Pipe) Skip(ctx *context.Context) bool { | ||||
| func (Pipe) Skip(ctx *context.Context) (bool, error) { | ||||
| 	if ctx.SkipAnnounce { | ||||
| 		return true | ||||
| 		return true, nil | ||||
| 	} | ||||
| 	if ctx.Config.Announce.Skip == "" { | ||||
| 		return false | ||||
| 	} | ||||
| 	skip, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Skip) | ||||
| 	if err != nil { | ||||
| 		log.Error("invalid announce.skip template, will skip the announcing step") | ||||
| 		return true | ||||
| 	} | ||||
| 	log.Debugf("announce.skip evaluated from %q to %q", ctx.Config.Announce.Skip, skip) | ||||
| 	return skip == "true" | ||||
| 	return tmpl.New(ctx).Bool(ctx.Config.Announce.Skip) | ||||
| } | ||||
|  | ||||
| // Run the pipe. | ||||
|   | ||||
| @@ -42,7 +42,9 @@ func TestSkip(t *testing.T) { | ||||
| 	t.Run("skip", func(t *testing.T) { | ||||
| 		ctx := context.New(config.Project{}) | ||||
| 		ctx.SkipAnnounce = true | ||||
| 		require.True(t, Pipe{}.Skip(ctx)) | ||||
| 		b, err := Pipe{}.Skip(ctx) | ||||
| 		require.NoError(t, err) | ||||
| 		require.True(t, b) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("skip on patches", func(t *testing.T) { | ||||
| @@ -52,21 +54,26 @@ func TestSkip(t *testing.T) { | ||||
| 			}, | ||||
| 		}) | ||||
| 		ctx.Semver.Patch = 1 | ||||
| 		require.True(t, Pipe{}.Skip(ctx)) | ||||
| 		b, err := Pipe{}.Skip(ctx) | ||||
| 		require.NoError(t, err) | ||||
| 		require.True(t, b) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("skip on invalid template", func(t *testing.T) { | ||||
| 	t.Run("invalid template", func(t *testing.T) { | ||||
| 		ctx := context.New(config.Project{ | ||||
| 			Announce: config.Announce{ | ||||
| 				Skip: "{{if eq .Patch 123}", | ||||
| 			}, | ||||
| 		}) | ||||
| 		ctx.Semver.Patch = 1 | ||||
| 		require.True(t, Pipe{}.Skip(ctx)) | ||||
| 		_, err := Pipe{}.Skip(ctx) | ||||
| 		require.Error(t, err) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("dont skip", func(t *testing.T) { | ||||
| 		require.False(t, Pipe{}.Skip(context.New(config.Project{}))) | ||||
| 		b, err := Pipe{}.Skip(context.New(config.Project{})) | ||||
| 		require.NoError(t, err) | ||||
| 		require.False(t, b) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("dont skip based on template", func(t *testing.T) { | ||||
| @@ -76,6 +83,8 @@ func TestSkip(t *testing.T) { | ||||
| 			}, | ||||
| 		}) | ||||
| 		ctx.Semver.Patch = 0 | ||||
| 		require.False(t, Pipe{}.Skip(ctx)) | ||||
| 		b, err := Pipe{}.Skip(ctx) | ||||
| 		require.NoError(t, err) | ||||
| 		require.False(t, b) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
							
								
								
									
										14
									
								
								internal/pipe/env/env.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								internal/pipe/env/env.go
									
									
									
									
										vendored
									
									
								
							| @@ -114,19 +114,13 @@ func (Pipe) Run(ctx *context.Context) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func isSkipRelease(ctx *context.Context) bool { | ||||
| 	d, err := tmpl.New(ctx).Apply(ctx.Config.Release.Disable) | ||||
| 	if err != nil { | ||||
| 		log.WithError(err).Error("could not execute release.disable template, will assume false") | ||||
| 		return false | ||||
| 	} | ||||
| 	return strings.ToLower(d) == "true" | ||||
| } | ||||
|  | ||||
| func checkErrors(ctx *context.Context, noTokens, noTokenErrs bool, gitlabTokenErr, githubTokenErr, giteaTokenErr error) error { | ||||
| 	if ctx.SkipTokenCheck || ctx.SkipPublish || isSkipRelease(ctx) { | ||||
| 	if ctx.SkipTokenCheck || ctx.SkipPublish { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if b, err := tmpl.New(ctx).Bool(ctx.Config.Release.Disable); err != nil || b { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if noTokens && noTokenErrs { | ||||
| 		return ErrMissingToken | ||||
|   | ||||
							
								
								
									
										3
									
								
								internal/pipe/env/env_test.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								internal/pipe/env/env_test.go
									
									
									
									
										vendored
									
									
								
							| @@ -5,6 +5,7 @@ import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/goreleaser/goreleaser/internal/testlib" | ||||
| 	"github.com/goreleaser/goreleaser/pkg/config" | ||||
| 	"github.com/goreleaser/goreleaser/pkg/context" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| @@ -247,7 +248,7 @@ func TestInvalidEnvReleaseDisabled(t *testing.T) { | ||||
| 				Disable: "{{ .Env.FOO }}", | ||||
| 			}, | ||||
| 		}) | ||||
| 		require.EqualError(t, Pipe{}.Run(ctx), ErrMissingToken.Error()) | ||||
| 		testlib.RequireTemplateError(t, Pipe{}.Run(ctx)) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io/fs" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/caarlos0/log" | ||||
| @@ -28,13 +27,9 @@ var ErrMultipleReleases = errors.New("multiple releases are defined. Only one is | ||||
| type Pipe struct{} | ||||
|  | ||||
| func (Pipe) String() string { return "scm releases" } | ||||
| func (Pipe) Skip(ctx *context.Context) bool { | ||||
| 	d, err := tmpl.New(ctx).Apply(ctx.Config.Release.Disable) | ||||
| 	if err != nil { | ||||
| 		log.WithError(err).Error("could not execute release.disable template, will assume false") | ||||
| 		return false | ||||
| 	} | ||||
| 	return strings.ToLower(d) == "true" | ||||
|  | ||||
| func (Pipe) Skip(ctx *context.Context) (bool, error) { | ||||
| 	return tmpl.New(ctx).Bool(ctx.Config.Release.Disable) | ||||
| } | ||||
|  | ||||
| // Default sets the pipe defaults. | ||||
| @@ -125,11 +120,11 @@ func doPublish(ctx *context.Context, client client.Client) error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	d, err := tmpl.New(ctx).Apply(ctx.Config.Release.SkipUpload) | ||||
| 	skipUpload, err := tmpl.New(ctx).Bool(ctx.Config.Release.SkipUpload) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if strings.ToLower(d) == "true" { | ||||
| 	if skipUpload { | ||||
| 		return pipe.Skip("release.skip_upload is set") | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -609,7 +609,9 @@ func TestSkip(t *testing.T) { | ||||
| 				Disable: "true", | ||||
| 			}, | ||||
| 		}) | ||||
| 		require.True(t, Pipe{}.Skip(ctx)) | ||||
| 		b, err := Pipe{}.Skip(ctx) | ||||
| 		require.NoError(t, err) | ||||
| 		require.True(t, b) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("skip tmpl", func(t *testing.T) { | ||||
| @@ -619,16 +621,19 @@ func TestSkip(t *testing.T) { | ||||
| 				Disable: "{{ .Env.FOO }}", | ||||
| 			}, | ||||
| 		}) | ||||
| 		require.True(t, Pipe{}.Skip(ctx)) | ||||
| 		b, err := Pipe{}.Skip(ctx) | ||||
| 		require.NoError(t, err) | ||||
| 		require.True(t, b) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("skip tmpl err", func(t *testing.T) { | ||||
| 	t.Run("tmpl err", func(t *testing.T) { | ||||
| 		ctx := context.New(config.Project{ | ||||
| 			Release: config.Release{ | ||||
| 				Disable: "{{ .Env.FOO }}", | ||||
| 			}, | ||||
| 		}) | ||||
| 		require.False(t, Pipe{}.Skip(ctx)) | ||||
| 		_, err := Pipe{}.Skip(ctx) | ||||
| 		require.Error(t, err) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("skip upload", func(t *testing.T) { | ||||
| @@ -657,6 +662,8 @@ func TestSkip(t *testing.T) { | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("dont skip", func(t *testing.T) { | ||||
| 		require.False(t, Pipe{}.Skip(context.New(config.Project{}))) | ||||
| 		b, err := Pipe{}.Skip(context.New(config.Project{})) | ||||
| 		require.NoError(t, err) | ||||
| 		require.False(t, b) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -142,11 +142,12 @@ func doPublish(ctx *context.Context, cl client.Client) error { | ||||
| 	if ctx.Config.Release.Draft { | ||||
| 		return pipe.Skip("release is marked as draft") | ||||
| 	} | ||||
| 	d, err := tmpl.New(ctx).Apply(ctx.Config.Release.Disable) | ||||
|  | ||||
| 	relDisabled, err := tmpl.New(ctx).Bool(ctx.Config.Release.Disable) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if strings.ToLower(d) == "true" { | ||||
| 	if relDisabled { | ||||
| 		return pipe.Skip("release is disabled") | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -190,6 +190,12 @@ func buildOptsToFields(opts build.Options) Fields { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Bool Apply the given string, and converts it to a bool. | ||||
| func (t *Template) Bool(s string) (bool, error) { | ||||
| 	r, err := t.Apply(s) | ||||
| 	return strings.TrimSpace(strings.ToLower(r)) == "true", err | ||||
| } | ||||
|  | ||||
| // Apply applies the given string against the Fields stored in the template. | ||||
| func (t *Template) Apply(s string) (string, error) { | ||||
| 	var out bytes.Buffer | ||||
|   | ||||
| @@ -360,3 +360,39 @@ func TestWithExtraFields(t *testing.T) { | ||||
| 	}).Apply("{{ .MyCustomField }}") | ||||
| 	require.Equal(t, "foo", out) | ||||
| } | ||||
|  | ||||
| func TestBool(t *testing.T) { | ||||
| 	t.Run("true", func(t *testing.T) { | ||||
| 		for _, v := range []string{ | ||||
| 			" TruE   ", | ||||
| 			"true", | ||||
| 			"TRUE", | ||||
| 		} { | ||||
| 			t.Run(v, func(t *testing.T) { | ||||
| 				ctx := context.New(config.Project{ | ||||
| 					Env: []string{"FOO=" + v}, | ||||
| 				}) | ||||
| 				b, err := New(ctx).Bool("{{.Env.FOO}}") | ||||
| 				require.NoError(t, err) | ||||
| 				require.True(t, b) | ||||
| 			}) | ||||
| 		} | ||||
| 	}) | ||||
| 	t.Run("false", func(t *testing.T) { | ||||
| 		for _, v := range []string{ | ||||
| 			"    ", | ||||
| 			"", | ||||
| 			"false", | ||||
| 			"yada yada", | ||||
| 		} { | ||||
| 			t.Run(v, func(t *testing.T) { | ||||
| 				ctx := context.New(config.Project{ | ||||
| 					Env: []string{"FOO=" + v}, | ||||
| 				}) | ||||
| 				b, err := New(ctx).Bool("{{.Env.FOO}}") | ||||
| 				require.NoError(t, err) | ||||
| 				require.False(t, b) | ||||
| 			}) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user