diff --git a/bake/bake.go b/bake/bake.go index 9263f5ba..14028ad0 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -70,8 +70,9 @@ func ParseFile(fn string) (*Config, error) { } type Config struct { - Groups []*Group `hcl:"group,block"` - Targets []*Target `hcl:"target,block"` + Variables []*Variable `json:"-" hcl:"variable,block"` + Groups []*Group `json:"groups" hcl:"group,block"` + Targets []*Target `json:"targets" hcl:"target,block"` } func mergeConfig(c1, c2 Config) Config { @@ -316,6 +317,11 @@ func (c Config) target(name string, visited map[string]struct{}, overrides map[s return tt, nil } +type Variable struct { + Name string `json:"-" hcl:"name,label"` + Default string `json:"default,omitempty" hcl:"default,optional"` +} + type Group struct { Name string `json:"-" hcl:"name,label"` Targets []string `json:"targets" hcl:"targets"` diff --git a/bake/hcl.go b/bake/hcl.go index bed4d995..75ae768f 100644 --- a/bake/hcl.go +++ b/bake/hcl.go @@ -11,9 +11,8 @@ import ( "github.com/zclconf/go-cty/cty/function/stdlib" ) -// Collection of functions expected to be generally useful in cty-using -// applications, which HCL supports. This set of functions will be available to -// be called in HCL files. +// Collection of generally useful functions in cty-using applications, which +// HCL supports. These functions are available for use in HCL files. var ( functions = map[string]function.Function{ "absolute": stdlib.AbsoluteFunc, @@ -64,11 +63,35 @@ var ( } ) +// Used in the first pass of decoding instead of the Config struct to disallow +// interpolation while parsing variable blocks. +type staticConfig struct { + Variables []*Variable `hcl:"variable,block"` + Remain hcl.Body `hcl:",remain"` +} + func ParseHCL(dt []byte, fn string) (*Config, error) { + var sc staticConfig + + // Decode only variable blocks without interpolation. + if err := hclsimple.Decode(fn, dt, nil, &sc); err != nil { + return nil, err + } + variables := make(map[string]cty.Value) + + // Set all variables to their default value if defined. + for _, variable := range sc.Variables { + variables[variable.Name] = cty.StringVal(variable.Default) + } + + // Override default with values from environment. for _, env := range os.Environ() { parts := strings.SplitN(env, "=", 2) - variables[parts[0]] = cty.StringVal(parts[1]) + name, value := parts[0], parts[1] + if _, ok := variables[name]; ok { + variables[name] = cty.StringVal(value) + } } ctx := &hcl.EvalContext{ @@ -77,6 +100,8 @@ func ParseHCL(dt []byte, fn string) (*Config, error) { } var c Config + + // Decode with variables and functions. if err := hclsimple.Decode(fn, dt, ctx, &c); err != nil { return nil, err } diff --git a/bake/hcl_test.go b/bake/hcl_test.go index e34ca3fb..c18c5286 100644 --- a/bake/hcl_test.go +++ b/bake/hcl_test.go @@ -8,9 +8,13 @@ import ( ) func TestParseHCL(t *testing.T) { - os.Setenv("IAMCROSS", "true") + os.Setenv("BUILD_NUMBER", "456") var dt = []byte(` + variable "BUILD_NUMBER" { + default = "123" + } + group "default" { targets = ["db", "webapp"] } @@ -24,7 +28,7 @@ func TestParseHCL(t *testing.T) { context = "./dir" dockerfile = "Dockerfile-alternate" args = { - buildno = "123" + buildno = "${BUILD_NUMBER}" } } @@ -38,7 +42,7 @@ func TestParseHCL(t *testing.T) { target "webapp-plus" { inherits = ["webapp", "cross"] args = { - IAMCROSS = "${IAMCROSS}" + IAMCROSS = "true" } } `) @@ -56,7 +60,7 @@ func TestParseHCL(t *testing.T) { require.Equal(t, c.Targets[1].Name, "webapp") require.Equal(t, 1, len(c.Targets[1].Args)) - require.Equal(t, "123", c.Targets[1].Args["buildno"]) + require.Equal(t, "456", c.Targets[1].Args["buildno"]) require.Equal(t, c.Targets[2].Name, "cross") require.Equal(t, 2, len(c.Targets[2].Platforms))