From 0044c28b1fbf1086c83c49ee8b3dc50a265ac700 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Thu, 13 Jan 2022 22:22:23 +0100 Subject: [PATCH] bake: keep target inheritance Signed-off-by: CrazyMax --- bake/bake.go | 14 ++--- bake/bake_test.go | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/bake/bake.go b/bake/bake.go index 16b4e37e..6848559b 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -389,10 +389,11 @@ func (c Config) group(name string, visited map[string]struct{}) []string { } func (c Config) ResolveTarget(name string, overrides map[string]map[string]Override) (*Target, error) { - t, err := c.target(name, map[string]struct{}{}, overrides) + t, err := c.target(name, map[string]*Target{}, overrides) if err != nil { return nil, err } + t.Inherits = nil if t.Context == nil { s := "." t.Context = &s @@ -404,11 +405,11 @@ func (c Config) ResolveTarget(name string, overrides map[string]map[string]Overr return t, nil } -func (c Config) target(name string, visited map[string]struct{}, overrides map[string]map[string]Override) (*Target, error) { - if _, ok := visited[name]; ok { - return nil, nil +func (c Config) target(name string, visited map[string]*Target, overrides map[string]map[string]Override) (*Target, error) { + if t, ok := visited[name]; ok { + return t, nil } - visited[name] = struct{}{} + visited[name] = nil var t *Target for _, target := range c.Targets { if target.Name == name { @@ -429,7 +430,6 @@ func (c Config) target(name string, visited map[string]struct{}, overrides map[s tt.Merge(t) } } - t.Inherits = nil m := defaultTarget() m.Merge(tt) m.Merge(t) @@ -437,8 +437,8 @@ func (c Config) target(name string, visited map[string]struct{}, overrides map[s if err := tt.AddOverrides(overrides[name]); err != nil { return nil, err } - tt.normalize() + visited[name] = tt return tt, nil } diff --git a/bake/bake_test.go b/bake/bake_test.go index 94355551..32023d5d 100644 --- a/bake/bake_test.go +++ b/bake/bake_test.go @@ -651,3 +651,140 @@ target "image" { require.Equal(t, "bar", *m["foo"].Dockerfile) require.Equal(t, "type=docker", m["image"].Outputs[0]) } + +func TestNestedInherits(t *testing.T) { + ctx := context.TODO() + + f := File{ + Name: "docker-bake.hcl", + Data: []byte(` +target "a" { + args = { + foo = "123" + bar = "234" + } +} +target "b" { + inherits = ["a"] + args = { + bar = "567" + } +} +target "c" { + inherits = ["a"] + args = { + baz = "890" + } +} +target "d" { + inherits = ["b", "c"] +}`)} + + cases := []struct { + name string + overrides []string + want map[string]string + }{ + { + name: "nested simple", + overrides: nil, + want: map[string]string{"bar": "234", "baz": "890", "foo": "123"}, + }, + { + name: "nested with overrides first", + overrides: []string{"a.args.foo=321", "b.args.bar=432"}, + want: map[string]string{"bar": "234", "baz": "890", "foo": "321"}, + }, + { + name: "nested with overrides last", + overrides: []string{"a.args.foo=321", "c.args.bar=432"}, + want: map[string]string{"bar": "432", "baz": "890", "foo": "321"}, + }, + } + for _, tt := range cases { + tt := tt + t.Run(tt.name, func(t *testing.T) { + m, g, err := ReadTargets(ctx, []File{f}, []string{"d"}, tt.overrides, nil) + require.NoError(t, err) + require.Equal(t, 1, len(g)) + require.Equal(t, []string{"d"}, g[0].Targets) + require.Equal(t, 1, len(m)) + require.Equal(t, tt.want, m["d"].Args) + }) + } +} + +func TestNestedInheritsWithGroup(t *testing.T) { + ctx := context.TODO() + + f := File{ + Name: "docker-bake.hcl", + Data: []byte(` +target "grandparent" { + output = ["type=docker"] + args = { + BAR = "fuu" + } +} +target "parent" { + inherits = ["grandparent"] + args = { + FOO = "bar" + } +} +target "child1" { + inherits = ["parent"] +} +target "child2" { + inherits = ["parent"] + args = { + FOO2 = "bar2" + } +} +group "default" { + targets = [ + "child1", + "child2" + ] +}`)} + + cases := []struct { + name string + overrides []string + wantch1 map[string]string + wantch2 map[string]string + }{ + { + name: "nested simple", + overrides: nil, + wantch1: map[string]string{"BAR": "fuu", "FOO": "bar"}, + wantch2: map[string]string{"BAR": "fuu", "FOO": "bar", "FOO2": "bar2"}, + }, + { + name: "nested with overrides first", + overrides: []string{"grandparent.args.BAR=fii", "child1.args.FOO=baaar"}, + wantch1: map[string]string{"BAR": "fii", "FOO": "baaar"}, + wantch2: map[string]string{"BAR": "fii", "FOO": "bar", "FOO2": "bar2"}, + }, + { + name: "nested with overrides last", + overrides: []string{"grandparent.args.BAR=fii", "child2.args.FOO=baaar"}, + wantch1: map[string]string{"BAR": "fii", "FOO": "bar"}, + wantch2: map[string]string{"BAR": "fii", "FOO": "baaar", "FOO2": "bar2"}, + }, + } + for _, tt := range cases { + tt := tt + t.Run(tt.name, func(t *testing.T) { + m, g, err := ReadTargets(ctx, []File{f}, []string{"default"}, tt.overrides, nil) + require.NoError(t, err) + require.Equal(t, 1, len(g)) + require.Equal(t, []string{"child1", "child2"}, g[0].Targets) + require.Equal(t, 2, len(m)) + require.Equal(t, tt.wantch1, m["child1"].Args) + require.Equal(t, []string{"type=docker"}, m["child1"].Outputs) + require.Equal(t, tt.wantch2, m["child2"].Args) + require.Equal(t, []string{"type=docker"}, m["child2"].Outputs) + }) + } +}