Skip to content

Commit f901709

Browse files
authored
Merge pull request #3207 from rrjjvv/show-var-types
Show types during variable list operation
2 parents a04b7d8 + b40b2ca commit f901709

4 files changed

Lines changed: 127 additions & 12 deletions

File tree

bake/hclparser/hclparser.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ type variable struct {
3838
Validations []*variableValidation `json:"validation,omitempty" hcl:"validation,block"`
3939
Body hcl.Body `json:"-" hcl:",body"`
4040
Remain hcl.Body `json:"-" hcl:",remain"`
41+
42+
// the type described by Type if it was specified
43+
constraint *cty.Type
4144
}
4245

4346
type variableValidation struct {
@@ -296,6 +299,9 @@ func (p *parser) resolveValue(ectx *hcl.EvalContext, name string) (err error) {
296299
return diags
297300
}
298301
typeSpecified = !varType.Equals(cty.DynamicPseudoType) || hcl.ExprAsKeyword(vr.Type) == "any"
302+
if typeSpecified {
303+
vr.constraint = &varType
304+
}
299305
}
300306

301307
if def == nil {
@@ -674,6 +680,7 @@ func (p *parser) validateVariables(vars map[string]*variable, ectx *hcl.EvalCont
674680
type Variable struct {
675681
Name string `json:"name"`
676682
Description string `json:"description,omitempty"`
683+
Type string `json:"type,omitempty"`
677684
Value *string `json:"value,omitempty"`
678685
}
679686

@@ -803,13 +810,31 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
803810
Name: p.vars[k].Name,
804811
Description: p.vars[k].Description,
805812
}
813+
tc := p.vars[k].constraint
814+
if tc != nil {
815+
v.Type = tc.FriendlyNameForConstraint()
816+
}
806817
if vv := p.ectx.Variables[k]; !vv.IsNull() {
807818
var s string
808-
switch vv.Type() {
809-
case cty.String:
810-
s = vv.AsString()
811-
case cty.Bool:
812-
s = strconv.FormatBool(vv.True())
819+
switch {
820+
case tc != nil:
821+
if bs, err := ctyjson.Marshal(vv, *tc); err == nil {
822+
s = string(bs)
823+
// untyped strings were always unquoted, so be consistent with typed strings as well
824+
if tc.Equals(cty.String) {
825+
s = strings.Trim(s, "\"")
826+
}
827+
}
828+
case vv.Type().IsPrimitiveType():
829+
// all primitives can convert to string, so error should never occur
830+
if val, err := convert.Convert(vv, cty.String); err == nil {
831+
s = val.AsString()
832+
}
833+
default:
834+
// must be an (inferred) tuple or object
835+
if bs, err := ctyjson.Marshal(vv, vv.Type()); err == nil {
836+
s = string(bs)
837+
}
813838
}
814839
v.Value = &s
815840
}

commands/bake.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ func printVars(w io.Writer, format string, vars []*hclparser.Variable) error {
663663
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
664664
defer tw.Flush()
665665

666-
tw.Write([]byte("VARIABLE\tVALUE\tDESCRIPTION\n"))
666+
tw.Write([]byte("VARIABLE\tTYPE\tVALUE\tDESCRIPTION\n"))
667667

668668
for _, v := range vars {
669669
var value string
@@ -672,7 +672,7 @@ func printVars(w io.Writer, format string, vars []*hclparser.Variable) error {
672672
} else {
673673
value = "<null>"
674674
}
675-
fmt.Fprintf(tw, "%s\t%s\t%s\n", v.Name, value, v.Description)
675+
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", v.Name, v.Type, value, v.Description)
676676
}
677677
return nil
678678
}

docs/reference/buildx_bake.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,15 @@ To list variables:
198198

199199
```console
200200
$ docker buildx bake --list=variables
201-
VARIABLE VALUE DESCRIPTION
202-
REGISTRY docker.io/username Registry and namespace
203-
IMAGE_NAME my-app Image name
204-
GO_VERSION <null>
201+
VARIABLE TYPE VALUE DESCRIPTION
202+
REGISTRY string docker.io/username Registry and namespace
203+
IMAGE_NAME string my-app Image name
204+
GO_VERSION <null>
205+
DEBUG bool false Add debug symbols
205206
```
206207

208+
Variable types will be shown when set using the `type` property in the Bake file.
209+
207210
By default, the output of `docker buildx bake --list` is presented in a table
208211
format. Alternatively, you can use a long-form CSV syntax and specify a
209212
`format` attribute to output the list in JSON.

tests/bake.go

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
7474
testBakeLoadPush,
7575
testListTargets,
7676
testListVariables,
77+
testListTypedVariables,
7778
testBakeCallCheck,
7879
testBakeCallCheckFlag,
7980
testBakeCallMetadata,
@@ -1737,7 +1738,93 @@ target "default" {
17371738
)
17381739
require.NoError(t, err, out)
17391740

1740-
require.Equal(t, "VARIABLE\tVALUE\tDESCRIPTION\nabc\t\t<null>\t\ndef\t\t\t\nfoo\t\tbar\tThis is foo", strings.TrimSpace(out))
1741+
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))
1742+
}
1743+
1744+
func testListTypedVariables(t *testing.T, sb integration.Sandbox) {
1745+
bakefile := []byte(`
1746+
variable "abc" {
1747+
type = string
1748+
default = "bar"
1749+
description = "This is abc"
1750+
}
1751+
variable "def" {
1752+
type = string
1753+
description = "simple type, no default"
1754+
}
1755+
variable "ghi" {
1756+
type = number
1757+
default = 99
1758+
description = "simple type w/ default"
1759+
}
1760+
variable "jkl" {
1761+
type = list(string)
1762+
default = ["hello"]
1763+
description = "collection with quoted strings"
1764+
}
1765+
variable "mno" {
1766+
type = list(number)
1767+
description = "collection, no default"
1768+
}
1769+
variable "pqr" {
1770+
type = tuple([number, string, bool])
1771+
default = [99, "99", true]
1772+
}
1773+
variable "stu" {
1774+
type = map(string)
1775+
default = {"foo": "bar"}
1776+
}
1777+
variable "vwx" {
1778+
type = set(bool)
1779+
default = null
1780+
description = "collection, null default"
1781+
}
1782+
1783+
// untyped, but previously didn't have its value output
1784+
variable "wxy" {
1785+
default = ["foo"]
1786+
description = "inferred tuple"
1787+
}
1788+
// untyped, but previously didn't have its value output
1789+
variable "xyz" {
1790+
default = {"foo": "bar"}
1791+
description = "inferred object"
1792+
}
1793+
// untyped, but previously didn't have its value output
1794+
variable "yza" {
1795+
default = true
1796+
description = "inferred bool"
1797+
}
1798+
target "default" {
1799+
}
1800+
`)
1801+
dir := tmpdir(
1802+
t,
1803+
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
1804+
)
1805+
1806+
out, err := bakeCmd(
1807+
sb,
1808+
withDir(dir),
1809+
withArgs("--list=variables"),
1810+
)
1811+
require.NoError(t, err, out)
1812+
require.Equal(t,
1813+
"VARIABLE\tTYPE\t\tVALUE\t\tDESCRIPTION\n"+
1814+
"abc\t\tstring\t\tbar\t\tThis is abc\n"+
1815+
"def\t\tstring\t\t<null>\t\tsimple type, no default\n"+
1816+
"ghi\t\tnumber\t\t99\t\tsimple type w/ default\n"+
1817+
"jkl\t\tlist of string\t[\"hello\"]\tcollection with quoted strings\n"+
1818+
"mno\t\tlist of number\t<null>\t\tcollection, no default\n"+
1819+
// the implementation for tuple's 'friendly name' is very basic
1820+
// and marked as TODO, so this may change/break at some point
1821+
"pqr\t\ttuple\t\t[99,\"99\",true]\t\n"+
1822+
"stu\t\tmap of string\t{\"foo\":\"bar\"}\t\n"+
1823+
"vwx\t\tset of bool\t<null>\t\tcollection, null default\n"+
1824+
"wxy\t\t\t\t[\"foo\"]\t\tinferred tuple\n"+
1825+
"xyz\t\t\t\t{\"foo\":\"bar\"}\tinferred object\n"+
1826+
"yza\t\t\t\ttrue\t\tinferred bool",
1827+
strings.TrimSpace(out))
17411828
}
17421829

17431830
func testBakeCallCheck(t *testing.T, sb integration.Sandbox) {

0 commit comments

Comments
 (0)