Skip to content

Commit

Permalink
Merge pull request docker#541 from tonistiigi/json-vars-attrs
Browse files Browse the repository at this point in the history
bake: allow attributes in global scope
  • Loading branch information
tonistiigi authored Mar 27, 2021
2 parents b2c7dc0 + f036bba commit 98d337a
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 4 deletions.
33 changes: 29 additions & 4 deletions bake/hcl.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ type StaticConfig struct {
Variables []*Variable `hcl:"variable,block"`
Remain hcl.Body `hcl:",remain"`

attrs hcl.Attributes

defaults map[string]*hcl.Attribute
env map[string]string
values map[string]cty.Value
Expand All @@ -146,6 +148,9 @@ func mergeStaticConfig(scs []*StaticConfig) *StaticConfig {
sc := scs[0]
for _, s := range scs[1:] {
sc.Variables = append(sc.Variables, s.Variables...)
for k, v := range s.attrs {
sc.attrs[k] = v
}
}
return sc
}
Expand All @@ -169,6 +174,12 @@ func (sc *StaticConfig) Values(withEnv bool) (map[string]cty.Value, error) {
sc.values = map[string]cty.Value{}
sc.progress = map[string]struct{}{}

for k := range sc.attrs {
if _, err := sc.resolveValue(k); err != nil {
return nil, err
}
}

for k := range sc.defaults {
if _, err := sc.resolveValue(k); err != nil {
return nil, err
Expand All @@ -192,10 +203,12 @@ func (sc *StaticConfig) resolveValue(name string) (v *cty.Value, err error) {
}
}()

def, ok := sc.defaults[name]

def, ok := sc.attrs[name]
if !ok {
return nil, errors.Errorf("undefined variable %q", name)
def, ok = sc.defaults[name]
if !ok {
return nil, errors.Errorf("undefined variable %q", name)
}
}

if def == nil {
Expand Down Expand Up @@ -233,7 +246,9 @@ func (sc *StaticConfig) resolveValue(name string) (v *cty.Value, err error) {
return nil, diags
}

if envv, ok := sc.env[name]; ok {
_, isVar := sc.defaults[name]

if envv, ok := sc.env[name]; ok && isVar {
if vv.Type().Equals(cty.Bool) {
b, err := strconv.ParseBool(envv)
if err != nil {
Expand Down Expand Up @@ -302,6 +317,16 @@ func parseHCLFile(dt []byte, fn string) (f *hcl.File, _ *StaticConfig, err error
return nil, nil, err
}

attrs, diags := f.Body.JustAttributes()
if diags.HasErrors() {
for _, d := range diags {
if d.Detail != "Blocks are not allowed here." {
return nil, nil, diags
}
}
}
sc.attrs = attrs

return f, &sc, nil
}

Expand Down
98 changes: 98 additions & 0 deletions bake/hcl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,3 +415,101 @@ func TestHCLVariableCycle(t *testing.T) {
require.Error(t, err)
require.Contains(t, err.Error(), "variable cycle not allowed")
}

func TestHCLAttrs(t *testing.T) {
dt := []byte(`
FOO="abc"
BAR="attr-${FOO}def"
target "app" {
args = {
"v1": BAR
}
}
`)

c, err := ParseFile(dt, "docker-bake.hcl")
require.NoError(t, err)

require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, "attr-abcdef", c.Targets[0].Args["v1"])

// env does not apply if no variable
os.Setenv("FOO", "bar")
c, err = ParseFile(dt, "docker-bake.hcl")
require.NoError(t, err)

require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, "attr-abcdef", c.Targets[0].Args["v1"])
// attr-multifile
}

func TestHCLAttrsCustomType(t *testing.T) {
dt := []byte(`
platforms=["linux/arm64", "linux/amd64"]
target "app" {
platforms = platforms
args = {
"v1": platforms[0]
}
}
`)

c, err := ParseFile(dt, "docker-bake.hcl")
require.NoError(t, err)

require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, []string{"linux/arm64", "linux/amd64"}, c.Targets[0].Platforms)
require.Equal(t, "linux/arm64", c.Targets[0].Args["v1"])
}

func TestHCLMultiFileAttrs(t *testing.T) {
os.Unsetenv("FOO")
dt := []byte(`
variable "FOO" {
default = "abc"
}
target "app" {
args = {
v1 = "pre-${FOO}"
}
}
`)
dt2 := []byte(`
FOO="def"
`)

c, err := parseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
})
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, "pre-def", c.Targets[0].Args["v1"])

os.Setenv("FOO", "ghi")

c, err = parseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
})
require.NoError(t, err)

require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, "pre-ghi", c.Targets[0].Args["v1"])
}

func TestJSONAttributes(t *testing.T) {
dt := []byte(`{"FOO": "abc", "variable": {"BAR": {"default": "def"}}, "target": { "app": { "args": {"v1": "pre-${FOO}-${BAR}"}} } }`)

c, err := ParseFile(dt, "docker-bake.json")
require.NoError(t, err)

require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, "pre-abc-def", c.Targets[0].Args["v1"])
}

0 comments on commit 98d337a

Please sign in to comment.