Skip to content

Commit

Permalink
fix(compiler): convert local templates to an engine field for nested …
Browse files Browse the repository at this point in the history
…templates (#916)

* fix(compiler): convert local templates to an engine field for nested templates

* add WithLocalTemplates test
  • Loading branch information
ecrupper authored Jul 25, 2023
1 parent 41fdfd1 commit acbb8f1
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 57 deletions.
2 changes: 1 addition & 1 deletion api/pipeline/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func CompilePipeline(c *gin.Context) {
compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u)

// compile the pipeline
pipeline, _, err := compiler.CompileLite(p.GetData(), true, true, nil)
pipeline, _, err := compiler.CompileLite(p.GetData(), true, true)
if err != nil {
retErr := fmt.Errorf("unable to compile pipeline %s: %w", entry, err)

Expand Down
2 changes: 1 addition & 1 deletion api/pipeline/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func ExpandPipeline(c *gin.Context) {
compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u)

// expand the templates in the pipeline
pipeline, _, err := compiler.CompileLite(p.GetData(), true, false, nil)
pipeline, _, err := compiler.CompileLite(p.GetData(), true, false)
if err != nil {
retErr := fmt.Errorf("unable to expand pipeline %s: %w", entry, err)

Expand Down
2 changes: 1 addition & 1 deletion api/pipeline/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func ValidatePipeline(c *gin.Context) {
}

// validate the pipeline
pipeline, _, err := compiler.CompileLite(p.GetData(), template, false, nil)
pipeline, _, err := compiler.CompileLite(p.GetData(), template, false)
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline %s: %w", entry, err)

Expand Down
5 changes: 4 additions & 1 deletion compiler/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Engine interface {
// CompileLite defines a function that produces an light executable
// representation of a pipeline from an object. This calls
// Parse internally to convert the object to a yaml configuration.
CompileLite(interface{}, bool, bool, []string) (*yaml.Build, *library.Pipeline, error)
CompileLite(interface{}, bool, bool) (*yaml.Build, *library.Pipeline, error)

// Duplicate defines a function that
// creates a clone of the Engine.
Expand Down Expand Up @@ -130,6 +130,9 @@ type Engine interface {
// WithLocal defines a function that sets
// the compiler local field in the Engine.
WithLocal(bool) Engine
// WithLocalTemplates defines a function that sets
// the compiler local templates field in the Engine.
WithLocalTemplates([]string) Engine
// WithMetadata defines a function that sets
// the compiler Metadata type in the Engine.
WithMetadata(*types.Metadata) Engine
Expand Down
43 changes: 5 additions & 38 deletions compiler/native/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err

switch {
case p.Metadata.RenderInline:
newPipeline, err := c.compileInline(p, nil, c.TemplateDepth)
newPipeline, err := c.compileInline(p, c.TemplateDepth)
if err != nil {
return nil, _pipeline, err
}
Expand All @@ -105,7 +105,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err
}

// CompileLite produces a partial of an executable pipeline from a yaml configuration.
func (c *client) CompileLite(v interface{}, template, substitute bool, localTemplates []string) (*yaml.Build, *library.Pipeline, error) {
func (c *client) CompileLite(v interface{}, template, substitute bool) (*yaml.Build, *library.Pipeline, error) {
p, data, err := c.Parse(v, c.repo.GetPipelineType(), new(yaml.Template))
if err != nil {
return nil, nil, err
Expand All @@ -117,7 +117,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp
_pipeline.SetType(c.repo.GetPipelineType())

if p.Metadata.RenderInline {
newPipeline, err := c.compileInline(p, localTemplates, c.TemplateDepth)
newPipeline, err := c.compileInline(p, c.TemplateDepth)
if err != nil {
return nil, _pipeline, err
}
Expand All @@ -134,24 +134,6 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp
// create map of templates for easy lookup
templates := mapFromTemplates(p.Templates)

if c.local {
for _, file := range localTemplates {
// local templates override format is <name>:<source>
//
// example: example:/path/to/template.yml
parts := strings.Split(file, ":")

// make sure the template was configured
_, ok := templates[parts[0]]
if !ok {
return nil, _pipeline, fmt.Errorf("template with name %s is not configured", parts[0])
}

// override the source for the given template
templates[parts[0]].Source = parts[1]
}
}

switch {
case len(p.Stages) > 0:
// inject the templates into the steps
Expand Down Expand Up @@ -194,7 +176,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp
}

// compileInline parses and expands out inline pipelines.
func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int) (*yaml.Build, error) {
func (c *client) compileInline(p *yaml.Build, depth int) (*yaml.Build, error) {
newPipeline := *p
newPipeline.Templates = yaml.TemplateSlice{}

Expand All @@ -206,21 +188,6 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int
}

for _, template := range p.Templates {
if c.local {
for _, file := range localTemplates {
// local templates override format is <name>:<source>
//
// example: example:/path/to/template.yml
parts := strings.Split(file, ":")

// make sure we're referencing the proper template
if parts[0] == template.Name {
// override the source for the given template
template.Source = parts[1]
}
}
}

bytes, err := c.getTemplate(template, template.Name)
if err != nil {
return nil, err
Expand All @@ -240,7 +207,7 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int

// if template parsed contains a template reference, recurse with decremented depth
if len(parsed.Templates) > 0 && parsed.Metadata.RenderInline {
parsed, err = c.compileInline(parsed, localTemplates, depth-1)
parsed, err = c.compileInline(parsed, depth-1)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/native/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3422,7 +3422,7 @@ func Test_CompileLite(t *testing.T) {
t.Errorf("Reading yaml file return err: %v", err)
}

got, _, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute, nil)
got, _, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute)
if (err != nil) != tt.wantErr {
t.Errorf("CompileLite() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
27 changes: 21 additions & 6 deletions compiler/native/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,30 @@ func (c *client) getTemplate(tmpl *yaml.Template, name string) ([]byte, error) {

switch {
case c.local:
a := &afero.Afero{
Fs: afero.NewOsFs(),
}
// iterate over locally provided templates
for _, t := range c.localTemplates {
parts := strings.Split(t, ":")
if len(parts) != 2 {
return nil, fmt.Errorf("local templates must be provided in the form <name>:<path>, got %s", t)
}

bytes, err = a.ReadFile(tmpl.Source)
if err != nil {
return bytes, err
if strings.EqualFold(tmpl.Name, parts[0]) {
a := &afero.Afero{
Fs: afero.NewOsFs(),
}

bytes, err = a.ReadFile(parts[1])
if err != nil {
return bytes, err
}

return bytes, nil
}
}

// no template found in provided templates, exit with error
return nil, fmt.Errorf("unable to find template %s: not supplied in list %s", tmpl.Name, c.localTemplates)

case strings.EqualFold(tmpl.Type, "github"):
// parse source from template
src, err := c.Github.Parse(tmpl.Source)
Expand Down
24 changes: 16 additions & 8 deletions compiler/native/native.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ type client struct {
CloneImage string
TemplateDepth int

build *library.Build
comment string
commit string
files []string
local bool
metadata *types.Metadata
repo *library.Repo
user *library.User
build *library.Build
comment string
commit string
files []string
local bool
localTemplates []string
metadata *types.Metadata
repo *library.Repo
user *library.User
}

// New returns a Pipeline implementation that integrates with the supported registries.
Expand Down Expand Up @@ -161,6 +162,13 @@ func (c *client) WithLocal(local bool) compiler.Engine {
return c
}

// WithLocalTemplates sets the compiler local templates in the Engine.
func (c *client) WithLocalTemplates(templates []string) compiler.Engine {
c.localTemplates = templates

return c
}

// WithMetadata sets the compiler metadata type in the Engine.
func (c *client) WithMetadata(m *types.Metadata) compiler.Engine {
if m != nil {
Expand Down
20 changes: 20 additions & 0 deletions compiler/native/native_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,26 @@ func TestNative_WithLocal(t *testing.T) {
}
}

func TestNative_WithLocalTemplates(t *testing.T) {
// setup types
set := flag.NewFlagSet("test", 0)
c := cli.NewContext(nil, set, nil)

localTemplates := []string{"example:tmpl.yml", "exmpl:template.yml"}
want, _ := New(c)
want.localTemplates = []string{"example:tmpl.yml", "exmpl:template.yml"}

// run test
got, err := New(c)
if err != nil {
t.Errorf("Unable to create new compiler: %v", err)
}

if !reflect.DeepEqual(got.WithLocalTemplates(localTemplates), want) {
t.Errorf("WithLocalTemplates is %v, want %v", got, want)
}
}

func TestNative_WithMetadata(t *testing.T) {
// setup types
set := flag.NewFlagSet("test", 0)
Expand Down

0 comments on commit acbb8f1

Please sign in to comment.