mirror of https://github.com/docker/buildx.git
bake: support null arg value
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
parent
e21f56e801
commit
df4957307f
55
bake/bake.go
55
bake/bake.go
|
@ -559,24 +559,24 @@ type Target struct {
|
|||
Attest []string `json:"attest,omitempty" hcl:"attest,optional" cty:"attest"`
|
||||
Inherits []string `json:"inherits,omitempty" hcl:"inherits,optional" cty:"inherits"`
|
||||
|
||||
Context *string `json:"context,omitempty" hcl:"context,optional" cty:"context"`
|
||||
Contexts map[string]string `json:"contexts,omitempty" hcl:"contexts,optional" cty:"contexts"`
|
||||
Dockerfile *string `json:"dockerfile,omitempty" hcl:"dockerfile,optional" cty:"dockerfile"`
|
||||
DockerfileInline *string `json:"dockerfile-inline,omitempty" hcl:"dockerfile-inline,optional" cty:"dockerfile-inline"`
|
||||
Args map[string]string `json:"args,omitempty" hcl:"args,optional" cty:"args"`
|
||||
Labels map[string]string `json:"labels,omitempty" hcl:"labels,optional" cty:"labels"`
|
||||
Tags []string `json:"tags,omitempty" hcl:"tags,optional" cty:"tags"`
|
||||
CacheFrom []string `json:"cache-from,omitempty" hcl:"cache-from,optional" cty:"cache-from"`
|
||||
CacheTo []string `json:"cache-to,omitempty" hcl:"cache-to,optional" cty:"cache-to"`
|
||||
Target *string `json:"target,omitempty" hcl:"target,optional" cty:"target"`
|
||||
Secrets []string `json:"secret,omitempty" hcl:"secret,optional" cty:"secret"`
|
||||
SSH []string `json:"ssh,omitempty" hcl:"ssh,optional" cty:"ssh"`
|
||||
Platforms []string `json:"platforms,omitempty" hcl:"platforms,optional" cty:"platforms"`
|
||||
Outputs []string `json:"output,omitempty" hcl:"output,optional" cty:"output"`
|
||||
Pull *bool `json:"pull,omitempty" hcl:"pull,optional" cty:"pull"`
|
||||
NoCache *bool `json:"no-cache,omitempty" hcl:"no-cache,optional" cty:"no-cache"`
|
||||
NetworkMode *string `json:"-" hcl:"-" cty:"-"`
|
||||
NoCacheFilter []string `json:"no-cache-filter,omitempty" hcl:"no-cache-filter,optional" cty:"no-cache-filter"`
|
||||
Context *string `json:"context,omitempty" hcl:"context,optional" cty:"context"`
|
||||
Contexts map[string]string `json:"contexts,omitempty" hcl:"contexts,optional" cty:"contexts"`
|
||||
Dockerfile *string `json:"dockerfile,omitempty" hcl:"dockerfile,optional" cty:"dockerfile"`
|
||||
DockerfileInline *string `json:"dockerfile-inline,omitempty" hcl:"dockerfile-inline,optional" cty:"dockerfile-inline"`
|
||||
Args map[string]*string `json:"args,omitempty" hcl:"args,optional" cty:"args"`
|
||||
Labels map[string]string `json:"labels,omitempty" hcl:"labels,optional" cty:"labels"`
|
||||
Tags []string `json:"tags,omitempty" hcl:"tags,optional" cty:"tags"`
|
||||
CacheFrom []string `json:"cache-from,omitempty" hcl:"cache-from,optional" cty:"cache-from"`
|
||||
CacheTo []string `json:"cache-to,omitempty" hcl:"cache-to,optional" cty:"cache-to"`
|
||||
Target *string `json:"target,omitempty" hcl:"target,optional" cty:"target"`
|
||||
Secrets []string `json:"secret,omitempty" hcl:"secret,optional" cty:"secret"`
|
||||
SSH []string `json:"ssh,omitempty" hcl:"ssh,optional" cty:"ssh"`
|
||||
Platforms []string `json:"platforms,omitempty" hcl:"platforms,optional" cty:"platforms"`
|
||||
Outputs []string `json:"output,omitempty" hcl:"output,optional" cty:"output"`
|
||||
Pull *bool `json:"pull,omitempty" hcl:"pull,optional" cty:"pull"`
|
||||
NoCache *bool `json:"no-cache,omitempty" hcl:"no-cache,optional" cty:"no-cache"`
|
||||
NetworkMode *string `json:"-" hcl:"-" cty:"-"`
|
||||
NoCacheFilter []string `json:"no-cache-filter,omitempty" hcl:"no-cache-filter,optional" cty:"no-cache-filter"`
|
||||
// IMPORTANT: if you add more fields here, do not forget to update newOverrides and docs/manuals/bake/file-definition.md.
|
||||
|
||||
// linked is a private field to mark a target used as a linked one
|
||||
|
@ -615,8 +615,11 @@ func (t *Target) Merge(t2 *Target) {
|
|||
t.DockerfileInline = t2.DockerfileInline
|
||||
}
|
||||
for k, v := range t2.Args {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if t.Args == nil {
|
||||
t.Args = map[string]string{}
|
||||
t.Args = map[string]*string{}
|
||||
}
|
||||
t.Args[k] = v
|
||||
}
|
||||
|
@ -688,9 +691,9 @@ func (t *Target) AddOverrides(overrides map[string]Override) error {
|
|||
return errors.Errorf("args require name")
|
||||
}
|
||||
if t.Args == nil {
|
||||
t.Args = map[string]string{}
|
||||
t.Args = map[string]*string{}
|
||||
}
|
||||
t.Args[keys[1]] = value
|
||||
t.Args[keys[1]] = &value
|
||||
case "contexts":
|
||||
if len(keys) != 2 {
|
||||
return errors.Errorf("contexts require name")
|
||||
|
@ -882,6 +885,14 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
|||
dockerfilePath = path.Join(contextPath, dockerfilePath)
|
||||
}
|
||||
|
||||
args := map[string]string{}
|
||||
for k, v := range t.Args {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
args[k] = *v
|
||||
}
|
||||
|
||||
noCache := false
|
||||
if t.NoCache != nil {
|
||||
noCache = *t.NoCache
|
||||
|
@ -922,7 +933,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
|||
bo := &build.Options{
|
||||
Inputs: bi,
|
||||
Tags: t.Tags,
|
||||
BuildArgs: t.Args,
|
||||
BuildArgs: args,
|
||||
Labels: t.Labels,
|
||||
NoCache: noCache,
|
||||
NoCacheFilter: t.NoCacheFilter,
|
||||
|
|
|
@ -2,7 +2,6 @@ package bake
|
|||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -42,7 +41,7 @@ target "webapp" {
|
|||
|
||||
require.Equal(t, "Dockerfile.webapp", *m["webapp"].Dockerfile)
|
||||
require.Equal(t, ".", *m["webapp"].Context)
|
||||
require.Equal(t, "webDEP", m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, ptrstr("webDEP"), m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, true, *m["webapp"].NoCache)
|
||||
require.Nil(t, m["webapp"].Pull)
|
||||
|
||||
|
@ -58,8 +57,7 @@ target "webapp" {
|
|||
|
||||
t.Run("ArgsOverrides", func(t *testing.T) {
|
||||
t.Run("leaf", func(t *testing.T) {
|
||||
os.Setenv("VAR_FROMENV"+t.Name(), "fromEnv")
|
||||
defer os.Unsetenv("VAR_FROM_ENV" + t.Name())
|
||||
t.Setenv("VAR_FROMENV"+t.Name(), "fromEnv")
|
||||
|
||||
m, g, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{
|
||||
"webapp.args.VAR_UNSET",
|
||||
|
@ -80,12 +78,12 @@ target "webapp" {
|
|||
_, isSet = m["webapp"].Args["VAR_EMPTY"]
|
||||
require.True(t, isSet, m["webapp"].Args["VAR_EMPTY"])
|
||||
|
||||
require.Equal(t, m["webapp"].Args["VAR_SET"], "bananas")
|
||||
require.Equal(t, ptrstr("bananas"), m["webapp"].Args["VAR_SET"])
|
||||
|
||||
require.Equal(t, m["webapp"].Args["VAR_FROMENV"+t.Name()], "fromEnv")
|
||||
require.Equal(t, ptrstr("fromEnv"), m["webapp"].Args["VAR_FROMENV"+t.Name()])
|
||||
|
||||
require.Equal(t, m["webapp"].Args["VAR_BOTH"], "webapp")
|
||||
require.Equal(t, m["webapp"].Args["VAR_INHERITED"], "override")
|
||||
require.Equal(t, ptrstr("webapp"), m["webapp"].Args["VAR_BOTH"])
|
||||
require.Equal(t, ptrstr("override"), m["webapp"].Args["VAR_INHERITED"])
|
||||
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"webapp"}, g["default"].Targets)
|
||||
|
@ -99,8 +97,8 @@ target "webapp" {
|
|||
}, nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, m["webapp"].Args["VAR_INHERITED"], "override")
|
||||
require.Equal(t, m["webapp"].Args["VAR_BOTH"], "webapp")
|
||||
require.Equal(t, ptrstr("override"), m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, ptrstr("webapp"), m["webapp"].Args["VAR_BOTH"])
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"webapp"}, g["default"].Targets)
|
||||
})
|
||||
|
@ -139,9 +137,9 @@ target "webapp" {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(m))
|
||||
require.Equal(t, "foo", *m["webapp"].Dockerfile)
|
||||
require.Equal(t, "webDEP", m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, ptrstr("webDEP"), m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, "foo", *m["webDEP"].Dockerfile)
|
||||
require.Equal(t, "webDEP", m["webDEP"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, ptrstr("webDEP"), m["webDEP"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, 1, len(g))
|
||||
sort.Strings(g["default"].Targets)
|
||||
require.Equal(t, []string{"webDEP", "webapp"}, g["default"].Targets)
|
||||
|
@ -173,7 +171,7 @@ target "webapp" {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(m))
|
||||
require.Equal(t, "foo", *m["webapp"].Dockerfile)
|
||||
require.Equal(t, "webDEP", m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, ptrstr("webDEP"), m["webapp"].Args["VAR_INHERITED"])
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"webapp"}, g["default"].Targets)
|
||||
},
|
||||
|
@ -300,8 +298,8 @@ services:
|
|||
require.True(t, ok)
|
||||
require.Equal(t, "Dockerfile.webapp", *m["webapp"].Dockerfile)
|
||||
require.Equal(t, ".", *m["webapp"].Context)
|
||||
require.Equal(t, "1", m["webapp"].Args["buildno"])
|
||||
require.Equal(t, "12", m["webapp"].Args["buildno2"])
|
||||
require.Equal(t, ptrstr("1"), m["webapp"].Args["buildno"])
|
||||
require.Equal(t, ptrstr("12"), m["webapp"].Args["buildno2"])
|
||||
|
||||
require.Equal(t, 1, len(g))
|
||||
sort.Strings(g["default"].Targets)
|
||||
|
@ -344,7 +342,7 @@ services:
|
|||
_, ok := m["web_app"]
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "Dockerfile.webapp", *m["web_app"].Dockerfile)
|
||||
require.Equal(t, "1", m["web_app"].Args["buildno"])
|
||||
require.Equal(t, ptrstr("1"), m["web_app"].Args["buildno"])
|
||||
|
||||
m, _, err = ReadTargets(ctx, []File{fp2}, []string{"web_app"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
@ -352,7 +350,7 @@ services:
|
|||
_, ok = m["web_app"]
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "Dockerfile", *m["web_app"].Dockerfile)
|
||||
require.Equal(t, "12", m["web_app"].Args["buildno2"])
|
||||
require.Equal(t, ptrstr("12"), m["web_app"].Args["buildno2"])
|
||||
|
||||
m, g, err := ReadTargets(ctx, []File{fp, fp2}, []string{"default"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
@ -361,8 +359,8 @@ services:
|
|||
require.True(t, ok)
|
||||
require.Equal(t, "Dockerfile.webapp", *m["web_app"].Dockerfile)
|
||||
require.Equal(t, ".", *m["web_app"].Context)
|
||||
require.Equal(t, "1", m["web_app"].Args["buildno"])
|
||||
require.Equal(t, "12", m["web_app"].Args["buildno2"])
|
||||
require.Equal(t, ptrstr("1"), m["web_app"].Args["buildno"])
|
||||
require.Equal(t, ptrstr("12"), m["web_app"].Args["buildno2"])
|
||||
|
||||
require.Equal(t, 1, len(g))
|
||||
sort.Strings(g["default"].Targets)
|
||||
|
@ -999,22 +997,22 @@ target "d" {
|
|||
cases := []struct {
|
||||
name string
|
||||
overrides []string
|
||||
want map[string]string
|
||||
want map[string]*string
|
||||
}{
|
||||
{
|
||||
name: "nested simple",
|
||||
overrides: nil,
|
||||
want: map[string]string{"bar": "234", "baz": "890", "foo": "123"},
|
||||
want: map[string]*string{"bar": ptrstr("234"), "baz": ptrstr("890"), "foo": ptrstr("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"},
|
||||
want: map[string]*string{"bar": ptrstr("234"), "baz": ptrstr("890"), "foo": ptrstr("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"},
|
||||
want: map[string]*string{"bar": ptrstr("432"), "baz": ptrstr("890"), "foo": ptrstr("321")},
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
|
@ -1067,26 +1065,26 @@ group "default" {
|
|||
cases := []struct {
|
||||
name string
|
||||
overrides []string
|
||||
wantch1 map[string]string
|
||||
wantch2 map[string]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"},
|
||||
wantch1: map[string]*string{"BAR": ptrstr("fuu"), "FOO": ptrstr("bar")},
|
||||
wantch2: map[string]*string{"BAR": ptrstr("fuu"), "FOO": ptrstr("bar"), "FOO2": ptrstr("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"},
|
||||
wantch1: map[string]*string{"BAR": ptrstr("fii"), "FOO": ptrstr("baaar")},
|
||||
wantch2: map[string]*string{"BAR": ptrstr("fii"), "FOO": ptrstr("bar"), "FOO2": ptrstr("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"},
|
||||
wantch1: map[string]*string{"BAR": ptrstr("fii"), "FOO": ptrstr("bar")},
|
||||
wantch2: map[string]*string{"BAR": ptrstr("fii"), "FOO": ptrstr("baaar"), "FOO2": ptrstr("bar2")},
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
|
@ -1285,8 +1283,70 @@ services:
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, "app", c.Targets[0].Name)
|
||||
require.Equal(t, "foo", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "bar", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("foo"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("bar"), c.Targets[0].Args["v2"])
|
||||
require.Equal(t, "dir", *c.Targets[0].Context)
|
||||
require.Equal(t, "Dockerfile-alternate", *c.Targets[0].Dockerfile)
|
||||
}
|
||||
|
||||
func TestHCLNullVars(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(
|
||||
`variable "FOO" {
|
||||
default = null
|
||||
}
|
||||
target "default" {
|
||||
args = {
|
||||
foo = FOO
|
||||
bar = "baz"
|
||||
}
|
||||
}`),
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"default"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(m))
|
||||
_, ok := m["default"]
|
||||
require.True(t, ok)
|
||||
|
||||
_, err = TargetsToBuildOpt(m, &Input{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, map[string]*string{"bar": ptrstr("baz")}, m["default"].Args)
|
||||
}
|
||||
|
||||
func TestJSONNullVars(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.json",
|
||||
Data: []byte(
|
||||
`{
|
||||
"variable": {
|
||||
"FOO": {
|
||||
"default": null
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"default": {
|
||||
"args": {
|
||||
"foo": "${FOO}",
|
||||
"bar": "baz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`),
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"default"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(m))
|
||||
_, ok := m["default"]
|
||||
require.True(t, ok)
|
||||
|
||||
_, err = TargetsToBuildOpt(m, &Input{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, map[string]*string{"bar": ptrstr("baz")}, m["default"].Args)
|
||||
}
|
||||
|
|
|
@ -193,16 +193,16 @@ func loadDotEnv(curenv map[string]string, workingDir string) (map[string]string,
|
|||
return curenv, nil
|
||||
}
|
||||
|
||||
func flatten(in compose.MappingWithEquals) compose.Mapping {
|
||||
func flatten(in compose.MappingWithEquals) map[string]*string {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := compose.Mapping{}
|
||||
out := map[string]*string{}
|
||||
for k, v := range in {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
out[k] = *v
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ secrets:
|
|||
require.Equal(t, "./dir", *c.Targets[1].Context)
|
||||
require.Equal(t, "Dockerfile-alternate", *c.Targets[1].Dockerfile)
|
||||
require.Equal(t, 1, len(c.Targets[1].Args))
|
||||
require.Equal(t, "123", c.Targets[1].Args["buildno"])
|
||||
require.Equal(t, ptrstr("123"), c.Targets[1].Args["buildno"])
|
||||
require.Equal(t, []string{"type=local,src=path/to/cache"}, c.Targets[1].CacheFrom)
|
||||
require.Equal(t, []string{"type=local,dest=path/to/cache"}, c.Targets[1].CacheTo)
|
||||
require.Equal(t, "none", *c.Targets[1].NetworkMode)
|
||||
|
@ -149,18 +149,15 @@ services:
|
|||
BRB: FOO
|
||||
`)
|
||||
|
||||
os.Setenv("FOO", "bar")
|
||||
defer os.Unsetenv("FOO")
|
||||
os.Setenv("BAR", "foo")
|
||||
defer os.Unsetenv("BAR")
|
||||
os.Setenv("ZZZ_BAR", "zzz_foo")
|
||||
defer os.Unsetenv("ZZZ_BAR")
|
||||
t.Setenv("FOO", "bar")
|
||||
t.Setenv("BAR", "foo")
|
||||
t.Setenv("ZZZ_BAR", "zzz_foo")
|
||||
|
||||
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, sliceToMap(os.Environ()))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "bar", c.Targets[0].Args["FOO"])
|
||||
require.Equal(t, "zzz_foo", c.Targets[0].Args["BAR"])
|
||||
require.Equal(t, "FOO", c.Targets[0].Args["BRB"])
|
||||
require.Equal(t, ptrstr("bar"), c.Targets[0].Args["FOO"])
|
||||
require.Equal(t, ptrstr("zzz_foo"), c.Targets[0].Args["BAR"])
|
||||
require.Equal(t, ptrstr("FOO"), c.Targets[0].Args["BRB"])
|
||||
}
|
||||
|
||||
func TestInconsistentComposeFile(t *testing.T) {
|
||||
|
@ -308,7 +305,7 @@ services:
|
|||
sort.Slice(c.Targets, func(i, j int) bool {
|
||||
return c.Targets[i].Name < c.Targets[j].Name
|
||||
})
|
||||
require.Equal(t, map[string]string{"CT_ECR": "foo", "CT_TAG": "bar"}, c.Targets[0].Args)
|
||||
require.Equal(t, map[string]*string{"CT_ECR": ptrstr("foo"), "CT_TAG": ptrstr("bar")}, c.Targets[0].Args)
|
||||
require.Equal(t, []string{"ct-addon:baz", "ct-addon:foo", "ct-addon:alp"}, c.Targets[0].Tags)
|
||||
require.Equal(t, []string{"linux/amd64", "linux/arm64"}, c.Targets[0].Platforms)
|
||||
require.Equal(t, []string{"user/app:cache", "type=local,src=path/to/cache"}, c.Targets[0].CacheFrom)
|
||||
|
@ -381,7 +378,7 @@ services:
|
|||
|
||||
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, map[string]string{"CT_ECR": "foo", "FOO": "bsdf -csdf", "NODE_ENV": "test"}, c.Targets[0].Args)
|
||||
require.Equal(t, map[string]*string{"CT_ECR": ptrstr("foo"), "FOO": ptrstr("bsdf -csdf"), "NODE_ENV": ptrstr("test")}, c.Targets[0].Args)
|
||||
}
|
||||
|
||||
func TestDotEnv(t *testing.T) {
|
||||
|
@ -405,7 +402,7 @@ services:
|
|||
Data: dt,
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, map[string]string{"FOO": "bar"}, c.Targets[0].Args)
|
||||
require.Equal(t, map[string]*string{"FOO": ptrstr("bar")}, c.Targets[0].Args)
|
||||
}
|
||||
|
||||
func TestPorts(t *testing.T) {
|
||||
|
@ -629,6 +626,22 @@ target "default" {
|
|||
}
|
||||
}
|
||||
|
||||
func TestComposeNullArgs(t *testing.T) {
|
||||
var dt = []byte(`
|
||||
services:
|
||||
scratch:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
FOO: null
|
||||
bar: "baz"
|
||||
`)
|
||||
|
||||
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, map[string]*string{"bar": ptrstr("baz")}, c.Targets[0].Args)
|
||||
}
|
||||
|
||||
// chdir changes the current working directory to the named directory,
|
||||
// and then restore the original working directory at the end of the test.
|
||||
func chdir(t *testing.T, dir string) {
|
||||
|
|
147
bake/hcl_test.go
147
bake/hcl_test.go
|
@ -1,7 +1,7 @@
|
|||
package bake
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -54,7 +54,7 @@ func TestHCLBasic(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, ptrstr("123"), c.Targets[1].Args["buildno"])
|
||||
|
||||
require.Equal(t, c.Targets[2].Name, "cross")
|
||||
require.Equal(t, 2, len(c.Targets[2].Platforms))
|
||||
|
@ -62,7 +62,7 @@ func TestHCLBasic(t *testing.T) {
|
|||
|
||||
require.Equal(t, c.Targets[3].Name, "webapp-plus")
|
||||
require.Equal(t, 1, len(c.Targets[3].Args))
|
||||
require.Equal(t, map[string]string{"IAMCROSS": "true"}, c.Targets[3].Args)
|
||||
require.Equal(t, map[string]*string{"IAMCROSS": ptrstr("true")}, c.Targets[3].Args)
|
||||
}
|
||||
|
||||
func TestHCLBasicInJSON(t *testing.T) {
|
||||
|
@ -114,7 +114,7 @@ func TestHCLBasicInJSON(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, ptrstr("123"), c.Targets[1].Args["buildno"])
|
||||
|
||||
require.Equal(t, c.Targets[2].Name, "cross")
|
||||
require.Equal(t, 2, len(c.Targets[2].Platforms))
|
||||
|
@ -122,7 +122,7 @@ func TestHCLBasicInJSON(t *testing.T) {
|
|||
|
||||
require.Equal(t, c.Targets[3].Name, "webapp-plus")
|
||||
require.Equal(t, 1, len(c.Targets[3].Args))
|
||||
require.Equal(t, map[string]string{"IAMCROSS": "true"}, c.Targets[3].Args)
|
||||
require.Equal(t, map[string]*string{"IAMCROSS": ptrstr("true")}, c.Targets[3].Args)
|
||||
}
|
||||
|
||||
func TestHCLWithFunctions(t *testing.T) {
|
||||
|
@ -147,7 +147,7 @@ func TestHCLWithFunctions(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "webapp")
|
||||
require.Equal(t, "124", c.Targets[0].Args["buildno"])
|
||||
require.Equal(t, ptrstr("124"), c.Targets[0].Args["buildno"])
|
||||
}
|
||||
|
||||
func TestHCLWithUserDefinedFunctions(t *testing.T) {
|
||||
|
@ -177,7 +177,7 @@ func TestHCLWithUserDefinedFunctions(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "webapp")
|
||||
require.Equal(t, "124", c.Targets[0].Args["buildno"])
|
||||
require.Equal(t, ptrstr("124"), c.Targets[0].Args["buildno"])
|
||||
}
|
||||
|
||||
func TestHCLWithVariables(t *testing.T) {
|
||||
|
@ -206,9 +206,9 @@ func TestHCLWithVariables(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "webapp")
|
||||
require.Equal(t, "123", c.Targets[0].Args["buildno"])
|
||||
require.Equal(t, ptrstr("123"), c.Targets[0].Args["buildno"])
|
||||
|
||||
os.Setenv("BUILD_NUMBER", "456")
|
||||
t.Setenv("BUILD_NUMBER", "456")
|
||||
|
||||
c, err = ParseFile(dt, "docker-bake.hcl")
|
||||
require.NoError(t, err)
|
||||
|
@ -219,7 +219,7 @@ func TestHCLWithVariables(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "webapp")
|
||||
require.Equal(t, "456", c.Targets[0].Args["buildno"])
|
||||
require.Equal(t, ptrstr("456"), c.Targets[0].Args["buildno"])
|
||||
}
|
||||
|
||||
func TestHCLWithVariablesInFunctions(t *testing.T) {
|
||||
|
@ -244,7 +244,7 @@ func TestHCLWithVariablesInFunctions(t *testing.T) {
|
|||
require.Equal(t, c.Targets[0].Name, "webapp")
|
||||
require.Equal(t, []string{"user/repo:v1"}, c.Targets[0].Tags)
|
||||
|
||||
os.Setenv("REPO", "docker/buildx")
|
||||
t.Setenv("REPO", "docker/buildx")
|
||||
|
||||
c, err = ParseFile(dt, "docker-bake.hcl")
|
||||
require.NoError(t, err)
|
||||
|
@ -280,10 +280,10 @@ func TestHCLMultiFileSharedVariables(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "pre-abc", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "abc-post", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("pre-abc"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("abc-post"), c.Targets[0].Args["v2"])
|
||||
|
||||
os.Setenv("FOO", "def")
|
||||
t.Setenv("FOO", "def")
|
||||
|
||||
c, err = ParseFiles([]File{
|
||||
{Data: dt, Name: "c1.hcl"},
|
||||
|
@ -293,12 +293,11 @@ func TestHCLMultiFileSharedVariables(t *testing.T) {
|
|||
|
||||
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"])
|
||||
require.Equal(t, "def-post", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("pre-def"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("def-post"), c.Targets[0].Args["v2"])
|
||||
}
|
||||
|
||||
func TestHCLVarsWithVars(t *testing.T) {
|
||||
os.Unsetenv("FOO")
|
||||
dt := []byte(`
|
||||
variable "FOO" {
|
||||
default = upper("${BASE}def")
|
||||
|
@ -330,10 +329,10 @@ func TestHCLVarsWithVars(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "pre--ABCDEF-", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "ABCDEF-post", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("pre--ABCDEF-"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("ABCDEF-post"), c.Targets[0].Args["v2"])
|
||||
|
||||
os.Setenv("BASE", "new")
|
||||
t.Setenv("BASE", "new")
|
||||
|
||||
c, err = ParseFiles([]File{
|
||||
{Data: dt, Name: "c1.hcl"},
|
||||
|
@ -343,12 +342,11 @@ func TestHCLVarsWithVars(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "pre--NEWDEF-", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "NEWDEF-post", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("pre--NEWDEF-"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("NEWDEF-post"), c.Targets[0].Args["v2"])
|
||||
}
|
||||
|
||||
func TestHCLTypedVariables(t *testing.T) {
|
||||
os.Unsetenv("FOO")
|
||||
dt := []byte(`
|
||||
variable "FOO" {
|
||||
default = 3
|
||||
|
@ -369,33 +367,80 @@ func TestHCLTypedVariables(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "lower", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "yes", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("lower"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("yes"), c.Targets[0].Args["v2"])
|
||||
|
||||
os.Setenv("FOO", "5.1")
|
||||
os.Setenv("IS_FOO", "0")
|
||||
t.Setenv("FOO", "5.1")
|
||||
t.Setenv("IS_FOO", "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, "higher", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "no", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("higher"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("no"), c.Targets[0].Args["v2"])
|
||||
|
||||
os.Setenv("FOO", "NaN")
|
||||
t.Setenv("FOO", "NaN")
|
||||
_, err = ParseFile(dt, "docker-bake.hcl")
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "failed to parse FOO as number")
|
||||
|
||||
os.Setenv("FOO", "0")
|
||||
os.Setenv("IS_FOO", "maybe")
|
||||
t.Setenv("FOO", "0")
|
||||
t.Setenv("IS_FOO", "maybe")
|
||||
|
||||
_, err = ParseFile(dt, "docker-bake.hcl")
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "failed to parse IS_FOO as bool")
|
||||
}
|
||||
|
||||
func TestHCLNullVariables(t *testing.T) {
|
||||
dt := []byte(`
|
||||
variable "FOO" {
|
||||
default = null
|
||||
}
|
||||
target "default" {
|
||||
args = {
|
||||
foo = FOO
|
||||
}
|
||||
}`)
|
||||
|
||||
c, err := ParseFile(dt, "docker-bake.hcl")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ptrstr(nil), c.Targets[0].Args["foo"])
|
||||
|
||||
t.Setenv("FOO", "bar")
|
||||
c, err = ParseFile(dt, "docker-bake.hcl")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ptrstr("bar"), c.Targets[0].Args["foo"])
|
||||
}
|
||||
|
||||
func TestJSONNullVariables(t *testing.T) {
|
||||
dt := []byte(`{
|
||||
"variable": {
|
||||
"FOO": {
|
||||
"default": null
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"default": {
|
||||
"args": {
|
||||
"foo": "${FOO}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
|
||||
c, err := ParseFile(dt, "docker-bake.json")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ptrstr(nil), c.Targets[0].Args["foo"])
|
||||
|
||||
t.Setenv("FOO", "bar")
|
||||
c, err = ParseFile(dt, "docker-bake.json")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ptrstr("bar"), c.Targets[0].Args["foo"])
|
||||
}
|
||||
|
||||
func TestHCLVariableCycle(t *testing.T) {
|
||||
dt := []byte(`
|
||||
variable "FOO" {
|
||||
|
@ -431,16 +476,16 @@ func TestHCLAttrs(t *testing.T) {
|
|||
|
||||
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"])
|
||||
require.Equal(t, ptrstr("attr-abcdef"), c.Targets[0].Args["v1"])
|
||||
|
||||
// env does not apply if no variable
|
||||
os.Setenv("FOO", "bar")
|
||||
t.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"])
|
||||
require.Equal(t, ptrstr("attr-abcdef"), c.Targets[0].Args["v1"])
|
||||
// attr-multifile
|
||||
}
|
||||
|
||||
|
@ -549,11 +594,10 @@ func TestHCLAttrsCustomType(t *testing.T) {
|
|||
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"])
|
||||
require.Equal(t, ptrstr("linux/arm64"), c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestHCLMultiFileAttrs(t *testing.T) {
|
||||
os.Unsetenv("FOO")
|
||||
dt := []byte(`
|
||||
variable "FOO" {
|
||||
default = "abc"
|
||||
|
@ -575,9 +619,9 @@ func TestHCLMultiFileAttrs(t *testing.T) {
|
|||
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"])
|
||||
require.Equal(t, ptrstr("pre-def"), c.Targets[0].Args["v1"])
|
||||
|
||||
os.Setenv("FOO", "ghi")
|
||||
t.Setenv("FOO", "ghi")
|
||||
|
||||
c, err = ParseFiles([]File{
|
||||
{Data: dt, Name: "c1.hcl"},
|
||||
|
@ -587,7 +631,7 @@ func TestHCLMultiFileAttrs(t *testing.T) {
|
|||
|
||||
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"])
|
||||
require.Equal(t, ptrstr("pre-ghi"), c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestJSONAttributes(t *testing.T) {
|
||||
|
@ -598,7 +642,7 @@ func TestJSONAttributes(t *testing.T) {
|
|||
|
||||
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"])
|
||||
require.Equal(t, ptrstr("pre-abc-def"), c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestJSONFunctions(t *testing.T) {
|
||||
|
@ -623,7 +667,7 @@ func TestJSONFunctions(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "pre-<FOO-abc>", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("pre-<FOO-abc>"), c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestHCLFunctionInAttr(t *testing.T) {
|
||||
|
@ -651,7 +695,7 @@ func TestHCLFunctionInAttr(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "FOO <> [baz]", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("FOO <> [baz]"), c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestHCLCombineCompose(t *testing.T) {
|
||||
|
@ -682,8 +726,8 @@ services:
|
|||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "foo", c.Targets[0].Args["v1"])
|
||||
require.Equal(t, "bar", c.Targets[0].Args["v2"])
|
||||
require.Equal(t, ptrstr("foo"), c.Targets[0].Args["v1"])
|
||||
require.Equal(t, ptrstr("bar"), c.Targets[0].Args["v2"])
|
||||
require.Equal(t, "dir", *c.Targets[0].Context)
|
||||
require.Equal(t, "Dockerfile-alternate", *c.Targets[0].Dockerfile)
|
||||
}
|
||||
|
@ -828,10 +872,10 @@ target "two" {
|
|||
require.Equal(t, 2, len(c.Targets))
|
||||
|
||||
require.Equal(t, c.Targets[0].Name, "one")
|
||||
require.Equal(t, map[string]string{"a": "pre-ghi-jkl"}, c.Targets[0].Args)
|
||||
require.Equal(t, map[string]*string{"a": ptrstr("pre-ghi-jkl")}, c.Targets[0].Args)
|
||||
|
||||
require.Equal(t, c.Targets[1].Name, "two")
|
||||
require.Equal(t, map[string]string{"b": "pre-jkl"}, c.Targets[1].Args)
|
||||
require.Equal(t, map[string]*string{"b": ptrstr("pre-jkl")}, c.Targets[1].Args)
|
||||
}
|
||||
|
||||
func TestEmptyVariableJSON(t *testing.T) {
|
||||
|
@ -882,3 +926,12 @@ func TestVarUnsupportedType(t *testing.T) {
|
|||
_, err := ParseFile(dt, "docker-bake.hcl")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func ptrstr(s interface{}) *string {
|
||||
var n *string = nil
|
||||
if reflect.ValueOf(s).Kind() == reflect.String {
|
||||
ss := s.(string)
|
||||
n = &ss
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ func appendJSONFuncCalls(exp hcl.Expression, m map[string]struct{}) error {
|
|||
|
||||
// hcl/v2/json/ast#stringVal
|
||||
val := src.FieldByName("Value")
|
||||
if val.IsZero() {
|
||||
if !val.IsValid() || val.IsZero() {
|
||||
return nil
|
||||
}
|
||||
rng := src.FieldByName("SrcRange")
|
||||
|
|
|
@ -281,19 +281,16 @@ func (p *parser) resolveValue(name string) (err error) {
|
|||
_, isVar := p.vars[name]
|
||||
|
||||
if envv, ok := p.opt.LookupVar(name); ok && isVar {
|
||||
if vv.Type().Equals(cty.Bool) {
|
||||
switch {
|
||||
case vv.Type().Equals(cty.Bool):
|
||||
b, err := strconv.ParseBool(envv)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %s as bool", name)
|
||||
}
|
||||
vv := cty.BoolVal(b)
|
||||
v = &vv
|
||||
return nil
|
||||
} else if vv.Type().Equals(cty.String) {
|
||||
vv := cty.StringVal(envv)
|
||||
v = &vv
|
||||
return nil
|
||||
} else if vv.Type().Equals(cty.Number) {
|
||||
vv = cty.BoolVal(b)
|
||||
case vv.Type().Equals(cty.String), vv.Type().Equals(cty.DynamicPseudoType):
|
||||
vv = cty.StringVal(envv)
|
||||
case vv.Type().Equals(cty.Number):
|
||||
n, err := strconv.ParseFloat(envv, 64)
|
||||
if err == nil && (math.IsNaN(n) || math.IsInf(n, 0)) {
|
||||
err = errors.Errorf("invalid number value")
|
||||
|
@ -301,10 +298,8 @@ func (p *parser) resolveValue(name string) (err error) {
|
|||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %s as number", name)
|
||||
}
|
||||
vv := cty.NumberVal(big.NewFloat(n))
|
||||
v = &vv
|
||||
return nil
|
||||
} else {
|
||||
vv = cty.NumberVal(big.NewFloat(n))
|
||||
default:
|
||||
// TODO: support lists with csv values
|
||||
return errors.Errorf("unsupported type %s for variable %s", vv.Type().FriendlyName(), name)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue