Show types during variable list operation

If a type was explicitly provided, it will be displayed in the variable
listing.  Inferred type names are not displayed, as they likely would
not match the user's intent.

Previously only `string` and `bool` default values were displayed in the
 listing.  All default values, regardless of type, are now displayed.

Signed-off-by: Roberto Villarreal <rrjjvv@yahoo.com>
This commit is contained in:
Roberto Villarreal
2025-05-29 17:36:46 -06:00
parent 542bda49f2
commit b40b2caf1a
4 changed files with 127 additions and 12 deletions
+30 -5
View File
@@ -38,6 +38,9 @@ type variable struct {
Validations []*variableValidation `json:"validation,omitempty" hcl:"validation,block"`
Body hcl.Body `json:"-" hcl:",body"`
Remain hcl.Body `json:"-" hcl:",remain"`
// the type described by Type if it was specified
constraint *cty.Type
}
type variableValidation struct {
@@ -296,6 +299,9 @@ func (p *parser) resolveValue(ectx *hcl.EvalContext, name string) (err error) {
return diags
}
typeSpecified = !varType.Equals(cty.DynamicPseudoType) || hcl.ExprAsKeyword(vr.Type) == "any"
if typeSpecified {
vr.constraint = &varType
}
}
if def == nil {
@@ -674,6 +680,7 @@ func (p *parser) validateVariables(vars map[string]*variable, ectx *hcl.EvalCont
type Variable struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Type string `json:"type,omitempty"`
Value *string `json:"value,omitempty"`
}
@@ -803,13 +810,31 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
Name: p.vars[k].Name,
Description: p.vars[k].Description,
}
tc := p.vars[k].constraint
if tc != nil {
v.Type = tc.FriendlyNameForConstraint()
}
if vv := p.ectx.Variables[k]; !vv.IsNull() {
var s string
switch vv.Type() {
case cty.String:
s = vv.AsString()
case cty.Bool:
s = strconv.FormatBool(vv.True())
switch {
case tc != nil:
if bs, err := ctyjson.Marshal(vv, *tc); err == nil {
s = string(bs)
// untyped strings were always unquoted, so be consistent with typed strings as well
if tc.Equals(cty.String) {
s = strings.Trim(s, "\"")
}
}
case vv.Type().IsPrimitiveType():
// all primitives can convert to string, so error should never occur
if val, err := convert.Convert(vv, cty.String); err == nil {
s = val.AsString()
}
default:
// must be an (inferred) tuple or object
if bs, err := ctyjson.Marshal(vv, vv.Type()); err == nil {
s = string(bs)
}
}
v.Value = &s
}
+2 -2
View File
@@ -663,7 +663,7 @@ func printVars(w io.Writer, format string, vars []*hclparser.Variable) error {
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
defer tw.Flush()
tw.Write([]byte("VARIABLE\tVALUE\tDESCRIPTION\n"))
tw.Write([]byte("VARIABLE\tTYPE\tVALUE\tDESCRIPTION\n"))
for _, v := range vars {
var value string
@@ -672,7 +672,7 @@ func printVars(w io.Writer, format string, vars []*hclparser.Variable) error {
} else {
value = "<null>"
}
fmt.Fprintf(tw, "%s\t%s\t%s\n", v.Name, value, v.Description)
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", v.Name, v.Type, value, v.Description)
}
return nil
}
+7 -4
View File
@@ -198,12 +198,15 @@ To list variables:
```console
$ docker buildx bake --list=variables
VARIABLE VALUE DESCRIPTION
REGISTRY docker.io/username Registry and namespace
IMAGE_NAME my-app Image name
GO_VERSION <null>
VARIABLE TYPE VALUE DESCRIPTION
REGISTRY string docker.io/username Registry and namespace
IMAGE_NAME string my-app Image name
GO_VERSION <null>
DEBUG bool false Add debug symbols
```
Variable types will be shown when set using the `type` property in the Bake file.
By default, the output of `docker buildx bake --list` is presented in a table
format. Alternatively, you can use a long-form CSV syntax and specify a
`format` attribute to output the list in JSON.
+88 -1
View File
@@ -74,6 +74,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakeLoadPush,
testListTargets,
testListVariables,
testListTypedVariables,
testBakeCallCheck,
testBakeCallCheckFlag,
testBakeCallMetadata,
@@ -1737,7 +1738,93 @@ target "default" {
)
require.NoError(t, err, out)
require.Equal(t, "VARIABLE\tVALUE\tDESCRIPTION\nabc\t\t<null>\t\ndef\t\t\t\nfoo\t\tbar\tThis is foo", strings.TrimSpace(out))
require.Equal(t, "VARIABLE\tTYPE\tVALUE\tDESCRIPTION\nabc\t\t\t<null>\t\ndef\t\t\t\t\nfoo\t\t\tbar\tThis is foo", strings.TrimSpace(out))
}
func testListTypedVariables(t *testing.T, sb integration.Sandbox) {
bakefile := []byte(`
variable "abc" {
type = string
default = "bar"
description = "This is abc"
}
variable "def" {
type = string
description = "simple type, no default"
}
variable "ghi" {
type = number
default = 99
description = "simple type w/ default"
}
variable "jkl" {
type = list(string)
default = ["hello"]
description = "collection with quoted strings"
}
variable "mno" {
type = list(number)
description = "collection, no default"
}
variable "pqr" {
type = tuple([number, string, bool])
default = [99, "99", true]
}
variable "stu" {
type = map(string)
default = {"foo": "bar"}
}
variable "vwx" {
type = set(bool)
default = null
description = "collection, null default"
}
// untyped, but previously didn't have its value output
variable "wxy" {
default = ["foo"]
description = "inferred tuple"
}
// untyped, but previously didn't have its value output
variable "xyz" {
default = {"foo": "bar"}
description = "inferred object"
}
// untyped, but previously didn't have its value output
variable "yza" {
default = true
description = "inferred bool"
}
target "default" {
}
`)
dir := tmpdir(
t,
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
)
out, err := bakeCmd(
sb,
withDir(dir),
withArgs("--list=variables"),
)
require.NoError(t, err, out)
require.Equal(t,
"VARIABLE\tTYPE\t\tVALUE\t\tDESCRIPTION\n"+
"abc\t\tstring\t\tbar\t\tThis is abc\n"+
"def\t\tstring\t\t<null>\t\tsimple type, no default\n"+
"ghi\t\tnumber\t\t99\t\tsimple type w/ default\n"+
"jkl\t\tlist of string\t[\"hello\"]\tcollection with quoted strings\n"+
"mno\t\tlist of number\t<null>\t\tcollection, no default\n"+
// the implementation for tuple's 'friendly name' is very basic
// and marked as TODO, so this may change/break at some point
"pqr\t\ttuple\t\t[99,\"99\",true]\t\n"+
"stu\t\tmap of string\t{\"foo\":\"bar\"}\t\n"+
"vwx\t\tset of bool\t<null>\t\tcollection, null default\n"+
"wxy\t\t\t\t[\"foo\"]\t\tinferred tuple\n"+
"xyz\t\t\t\t{\"foo\":\"bar\"}\tinferred object\n"+
"yza\t\t\t\ttrue\t\tinferred bool",
strings.TrimSpace(out))
}
func testBakeCallCheck(t *testing.T, sb integration.Sandbox) {