Skip to content

Commit

Permalink
Add function that returns all default builtin template definitions (#260
Browse files Browse the repository at this point in the history
)
  • Loading branch information
JacobsonMT authored Jan 10, 2025
1 parent 0f317eb commit 267368f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 4 deletions.
32 changes: 28 additions & 4 deletions templates/default_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package templates
import (
"context"
"net/url"
"strings"
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"

"github.com/grafana/alerting/logging"
)
Expand Down Expand Up @@ -127,6 +129,19 @@ func TestDefaultTemplateString(t *testing.T) {
l := &logging.FakeLogger{}
expand, _ := TmplText(context.Background(), tmpl, alerts, l, &tmplErr)

tmplDef, err := DefaultTemplate()
require.NoError(t, err)

tmplFromDefinition, err := newTemplate()
require.NoError(t, err)
// Parse default template string.
err = tmplFromDefinition.Parse(strings.NewReader(tmplDef.Template))
require.NoError(t, err)
tmplFromDefinition.ExternalURL = externalURL

var tmplDefErr error
expandFromDefinition, _ := TmplText(context.Background(), tmplFromDefinition, alerts, l, &tmplDefErr)

cases := []struct {
templateString string
expected string
Expand Down Expand Up @@ -305,10 +320,19 @@ Silence: [http://localhost/grafana/alerting/silence/new?alertmanager=grafana&mat

for _, c := range cases {
t.Run(c.templateString, func(t *testing.T) {
act := expand(c.templateString)
require.NoError(t, tmplErr)
require.Equal(t, c.expected, act)
t.Run("FromContent", func(t *testing.T) {
act := expand(c.templateString)
require.NoError(t, tmplErr)
require.Equal(t, c.expected, act)
})

t.Run("DefaultTemplate", func(t *testing.T) {
act := expandFromDefinition(c.templateString)
require.NoError(t, tmplDefErr)
require.Equal(t, c.expected, act)
})
})
}
require.NoError(t, tmplErr)
require.NoError(t, tmplDefErr)
}
50 changes: 50 additions & 0 deletions templates/template_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package templates
import (
"context"
"encoding/json"
"fmt"
tmplhtml "html/template"
"net/url"
"path"
"slices"
"sort"
"strings"
tmpltext "text/template"
"time"

"github.com/go-kit/log"
Expand Down Expand Up @@ -65,6 +69,52 @@ type ExtendedData struct {
ExternalURL string `json:"externalURL"`
}

var DefaultTemplateName = "__default__"

// DefaultTemplate returns a new Template with all default templates parsed.
func DefaultTemplate(options ...template.Option) (TemplateDefinition, error) {
// We cannot simply append the text of each default file together as there can be (and are) duplicate template
// names. Duplicate templates should override when parsed from separate files but will fail to parse if both are in
// the same file.
// So, instead we allow tmpltext to combine the templates and then convert it to a string afterwards.
// The underlying template is not accessible, so we capture it via template.Option.
var newTextTmpl *tmpltext.Template
var captureTemplate template.Option = func(text *tmpltext.Template, _ *tmplhtml.Template) {
newTextTmpl = text
}

// Call FromContent without any user-provided templates to get the combined default template.
_, err := FromContent(nil, append(options, captureTemplate)...)
if err != nil {
return TemplateDefinition{}, err
}

var combinedTemplate strings.Builder
tmpls := newTextTmpl.Templates()
// Sort for a consistent order.
slices.SortFunc(tmpls, func(a, b *tmpltext.Template) int {
return strings.Compare(a.Name(), b.Name())
})

// Recreate the "define" blocks for all templates. Would be nice to have a more direct way to do this.
for _, tmpl := range tmpls {
if tmpl.Name() != "" {
def := tmpl.Tree.Root.String()
if tmpl.Name() == "__text_values_list" {
// Temporary fix for https://github.com/golang/go/commit/6fea4094242fe4e7be8bd7ec0b55df9f6df3f025.
// TODO: Can remove with GO v1.24.
def = strings.Replace(def, "$first := false", "$first = false", 1)
}

combinedTemplate.WriteString(fmt.Sprintf("{{ define \"%s\" }}%s{{ end }}\n\n", tmpl.Name(), def))
}
}
return TemplateDefinition{
Name: DefaultTemplateName,
Template: combinedTemplate.String(),
}, nil
}

// FromContent calls Parse on all provided template content and returns the resulting Template. Content equivalent to templates.FromGlobs.
func FromContent(tmpls []string, options ...template.Option) (*Template, error) {
t, err := newTemplate(options...)
Expand Down

0 comments on commit 267368f

Please sign in to comment.