github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/tag/custom_template.go (about) 1 /* 2 Copyright 2020 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tag 18 19 import ( 20 "bytes" 21 "context" 22 "fmt" 23 "text/template" 24 25 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log" 26 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 27 ) 28 29 // customTemplateTagger implements Tagger 30 type customTemplateTagger struct { 31 Template *template.Template 32 Components map[string]Tagger 33 } 34 35 // NewCustomTemplateTagger creates a new customTemplateTagger 36 func NewCustomTemplateTagger(t string, components map[string]Tagger) (Tagger, error) { 37 tmpl, err := ParseCustomTemplate(t) 38 if err != nil { 39 return nil, fmt.Errorf("parsing template: %w", err) 40 } 41 42 return &customTemplateTagger{ 43 Template: tmpl, 44 Components: components, 45 }, nil 46 } 47 48 // GenerateTag generates a tag from a template referencing tagging strategies. 49 func (t *customTemplateTagger) GenerateTag(ctx context.Context, image latest.Artifact) (string, error) { 50 customMap, err := t.EvaluateComponents(ctx, image) 51 if err != nil { 52 return "", err 53 } 54 55 // missingkey=error throws error when map is indexed with an undefined key 56 tag, err := ExecuteCustomTemplate(t.Template.Option("missingkey=error"), customMap) 57 if err != nil { 58 return "", err 59 } 60 61 return tag, nil 62 } 63 64 // EvaluateComponents creates a custom mapping of component names to their tagger string representation. 65 func (t *customTemplateTagger) EvaluateComponents(ctx context.Context, image latest.Artifact) (map[string]string, error) { 66 customMap := map[string]string{} 67 68 gitTagger, _ := NewGitCommit("", "", false) 69 dateTimeTagger := NewDateTimeTagger("", "") 70 71 for k, v := range map[string]Tagger{"GIT": gitTagger, "DATE": dateTimeTagger, "SHA": &ChecksumTagger{}} { 72 tag, _ := v.GenerateTag(ctx, image) 73 customMap[k] = tag 74 } 75 76 for k, v := range t.Components { 77 if _, ok := v.(*customTemplateTagger); ok { 78 return nil, fmt.Errorf("invalid component specified in custom template: %v", v) 79 } 80 tag, err := v.GenerateTag(ctx, image) 81 if err != nil { 82 return nil, fmt.Errorf("evaluating custom template component: %w", err) 83 } 84 customMap[k] = tag 85 } 86 return customMap, nil 87 } 88 89 // ParseCustomTemplate is a simple wrapper to parse an custom template. 90 func ParseCustomTemplate(t string) (*template.Template, error) { 91 return template.New("customTemplate").Parse(t) 92 } 93 94 // ExecuteCustomTemplate executes a customTemplate against a custom map. 95 func ExecuteCustomTemplate(customTemplate *template.Template, customMap map[string]string) (string, error) { 96 var buf bytes.Buffer 97 log.Entry(context.TODO()).Debugf("Executing custom template %v with custom map %v", customTemplate, customMap) 98 if err := customTemplate.Execute(&buf, customMap); err != nil { 99 return "", fmt.Errorf("executing template: %w", err) 100 } 101 return buf.String(), nil 102 }