bake: keep escaped interpolation in print output

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2025-04-08 17:06:45 +02:00
parent 98c3abb756
commit a91db7ccc9
No known key found for this signature in database
GPG Key ID: ADE44D8C9D44FBE4
2 changed files with 97 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package bake
import ( import (
"context" "context"
"encoding" "encoding"
"encoding/json"
"io" "io"
"maps" "maps"
"os" "os"
@ -733,6 +734,41 @@ type Target struct {
linked bool linked bool
} }
func (t *Target) MarshalJSON() ([]byte, error) {
tgt := *t
esc := func(s string) string {
return strings.ReplaceAll(strings.ReplaceAll(s, "${", "$${"), "%{", "%%{")
}
tgt.Annotations = slices.Clone(t.Annotations)
for i, v := range tgt.Annotations {
tgt.Annotations[i] = esc(v)
}
if tgt.DockerfileInline != nil {
escaped := esc(*tgt.DockerfileInline)
tgt.DockerfileInline = &escaped
}
tgt.Labels = maps.Clone(t.Labels)
for k, v := range t.Labels {
if v != nil {
escaped := esc(*v)
tgt.Labels[k] = &escaped
}
}
tgt.Args = maps.Clone(t.Args)
for k, v := range t.Args {
if v != nil {
escaped := esc(*v)
tgt.Args[k] = &escaped
}
}
return json.Marshal(tgt)
}
var ( var (
_ hclparser.WithEvalContexts = &Target{} _ hclparser.WithEvalContexts = &Target{}
_ hclparser.WithGetName = &Target{} _ hclparser.WithGetName = &Target{}

View File

@ -40,6 +40,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakePrint, testBakePrint,
testBakePrintSensitive, testBakePrintSensitive,
testBakePrintOverrideEmpty, testBakePrintOverrideEmpty,
testBakePrintKeepEscaped,
testBakeLocal, testBakeLocal,
testBakeLocalMulti, testBakeLocalMulti,
testBakeRemote, testBakeRemote,
@ -329,6 +330,66 @@ target "default" {
}`, stdout.String()) }`, stdout.String())
} }
func testBakePrintKeepEscaped(t *testing.T, sb integration.Sandbox) {
bakefile := []byte(`
target "default" {
dockerfile-inline = <<EOT
ARG VERSION=latest
FROM alpine:$${VERSION}
EOT
args = {
VERSION = "3.21"
}
annotations = [
"org.opencontainers.image.authors=$${user}"
]
labels = {
foo = "hello %%{bar}"
}
}
`)
dir := tmpdir(t, fstest.CreateFile("docker-bake.hcl", bakefile, 0600))
cmd := buildxCmd(sb, withDir(dir), withArgs("bake", "--print"))
stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
require.NoError(t, cmd.Run(), stdout.String(), stderr.String())
require.JSONEq(t, `{
"group": {
"default": {
"targets": [
"default"
]
}
},
"target": {
"default": {
"annotations": [
"org.opencontainers.image.authors=$${user}"
],
"context": ".",
"dockerfile": "Dockerfile",
"dockerfile-inline": "ARG VERSION=latest\nFROM alpine:$${VERSION}\n",
"args": {
"VERSION": "3.21"
},
"labels": {
"foo": "hello %%{bar}"
}
}
}
}`, stdout.String())
// test build with definition from print output
dir = tmpdir(t, fstest.CreateFile("docker-bake.json", stdout.Bytes(), 0600))
cmd = buildxCmd(sb, withDir(dir), withArgs("bake"))
out, err := cmd.CombinedOutput()
require.NoError(t, err, string(out))
}
func testBakeLocal(t *testing.T, sb integration.Sandbox) { func testBakeLocal(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(` dockerfile := []byte(`
FROM scratch FROM scratch