feat: add template.FromGlobsWithAdditionalFuncs (#3174)
* refactor: add Options to the template.FromGlob function to allow customizing the Template Signed-off-by: Martin Chodur <m.chodur@seznam.cz>
This commit is contained in:
parent
d9c847e38b
commit
26cbd6bd86
|
@ -84,7 +84,7 @@ func CheckConfig(args []string) error {
|
|||
fmt.Printf(" - %d receivers\n", len(cfg.Receivers))
|
||||
fmt.Printf(" - %d templates\n", len(cfg.Templates))
|
||||
if len(cfg.Templates) > 0 {
|
||||
_, err = template.FromGlobs(cfg.Templates...)
|
||||
_, err = template.FromGlobs(cfg.Templates)
|
||||
if err != nil {
|
||||
fmt.Printf(" FAILED: %s\n", err)
|
||||
failed++
|
||||
|
|
|
@ -107,7 +107,7 @@ func configureTemplateRenderCmd(cc *kingpin.CmdClause) {
|
|||
}
|
||||
|
||||
func (c *templateRenderCmd) render(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
tmpl, err := template.FromGlobs(c.templateFilesGlobs...)
|
||||
tmpl, err := template.FromGlobs(c.templateFilesGlobs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -419,7 +419,7 @@ func run() int {
|
|||
configLogger,
|
||||
)
|
||||
configCoordinator.Subscribe(func(conf *config.Config) error {
|
||||
tmpl, err = template.FromGlobs(conf.Templates...)
|
||||
tmpl, err = template.FromGlobs(conf.Templates)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse templates")
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ func notifyEmailWithContext(ctx context.Context, cfg *config.EmailConfig, server
|
|||
return nil, false, err
|
||||
}
|
||||
|
||||
tmpl, err := template.FromGlobs()
|
||||
tmpl, err := template.FromGlobs([]string{})
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ func DefaultRetryCodes() []int {
|
|||
|
||||
// CreateTmpl returns a ready-to-use template.
|
||||
func CreateTmpl(t *testing.T) *template.Template {
|
||||
tmpl, err := template.FromGlobs()
|
||||
tmpl, err := template.FromGlobs([]string{})
|
||||
require.NoError(t, err)
|
||||
tmpl.ExternalURL, _ = url.Parse("http://am")
|
||||
return tmpl
|
||||
|
|
|
@ -42,16 +42,24 @@ type Template struct {
|
|||
ExternalURL *url.URL
|
||||
}
|
||||
|
||||
// Option is generic modifier of the text and html templates used by a Template.
|
||||
type Option func(text *tmpltext.Template, html *tmplhtml.Template)
|
||||
|
||||
// FromGlobs calls ParseGlob on all path globs provided and returns the
|
||||
// resulting Template.
|
||||
func FromGlobs(paths ...string) (*Template, error) {
|
||||
// resulting Template. Options allows customization of the text and html templates in given order.
|
||||
// The DefaultFuncs have precedence over any added custom functions.
|
||||
func FromGlobs(paths []string, options ...Option) (*Template, error) {
|
||||
t := &Template{
|
||||
text: tmpltext.New("").Option("missingkey=zero"),
|
||||
html: tmplhtml.New("").Option("missingkey=zero"),
|
||||
}
|
||||
|
||||
t.text = t.text.Funcs(tmpltext.FuncMap(DefaultFuncs))
|
||||
t.html = t.html.Funcs(tmplhtml.FuncMap(DefaultFuncs))
|
||||
for _, o := range options {
|
||||
o(t.text, t.html)
|
||||
}
|
||||
|
||||
t.text.Funcs(tmpltext.FuncMap(DefaultFuncs))
|
||||
t.html.Funcs(tmplhtml.FuncMap(DefaultFuncs))
|
||||
|
||||
defaultTemplates := []string{"default.tmpl", "email.tmpl"}
|
||||
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
tmplhtml "html/template"
|
||||
"net/url"
|
||||
"testing"
|
||||
tmpltext "text/template"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -277,7 +279,7 @@ func TestData(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTemplateExpansion(t *testing.T) {
|
||||
tmpl, err := FromGlobs()
|
||||
tmpl, err := FromGlobs([]string{})
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, tc := range []struct {
|
||||
|
@ -387,3 +389,67 @@ func TestTemplateExpansion(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateExpansionWithOptions(t *testing.T) {
|
||||
testOptionWithAdditionalFuncs := func(funcs FuncMap) Option {
|
||||
return func(text *tmpltext.Template, html *tmplhtml.Template) {
|
||||
text.Funcs(tmpltext.FuncMap(funcs))
|
||||
html.Funcs(tmplhtml.FuncMap(funcs))
|
||||
}
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
options []Option
|
||||
title string
|
||||
in string
|
||||
data interface{}
|
||||
html bool
|
||||
|
||||
exp string
|
||||
fail bool
|
||||
}{
|
||||
{
|
||||
title: "Test custom function",
|
||||
options: []Option{testOptionWithAdditionalFuncs(FuncMap{"printFoo": func() string { return "foo" }})},
|
||||
in: `{{ printFoo }}`,
|
||||
exp: "foo",
|
||||
},
|
||||
{
|
||||
title: "Test Default function with additional function added",
|
||||
options: []Option{testOptionWithAdditionalFuncs(FuncMap{"printFoo": func() string { return "foo" }})},
|
||||
in: `{{ toUpper "test" }}`,
|
||||
exp: "TEST",
|
||||
},
|
||||
{
|
||||
title: "Test custom function is overridden by the DefaultFuncs",
|
||||
options: []Option{testOptionWithAdditionalFuncs(FuncMap{"toUpper": func(s string) string { return "foo" }})},
|
||||
in: `{{ toUpper "test" }}`,
|
||||
exp: "TEST",
|
||||
},
|
||||
{
|
||||
title: "Test later Option overrides the previous",
|
||||
options: []Option{
|
||||
testOptionWithAdditionalFuncs(FuncMap{"printFoo": func() string { return "foo" }}),
|
||||
testOptionWithAdditionalFuncs(FuncMap{"printFoo": func() string { return "bar" }}),
|
||||
},
|
||||
in: `{{ printFoo }}`,
|
||||
exp: "bar",
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.title, func(t *testing.T) {
|
||||
tmpl, err := FromGlobs([]string{}, tc.options...)
|
||||
require.NoError(t, err)
|
||||
f := tmpl.ExecuteTextString
|
||||
if tc.html {
|
||||
f = tmpl.ExecuteHTMLString
|
||||
}
|
||||
got, err := f(tc.in, tc.data)
|
||||
if tc.fail {
|
||||
require.NotNil(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue