mirror of https://github.com/docker/buildx.git
Merge pull request #2640 from crazy-max/call-metadata
support metadata file with call flag for build and bake commands
This commit is contained in:
commit
16860e6dd2
|
@ -252,13 +252,15 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
|
||||||
if progressMode != progressui.QuietMode && progressMode != progressui.RawJSONMode {
|
if progressMode != progressui.QuietMode && progressMode != progressui.RawJSONMode {
|
||||||
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
|
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
|
||||||
}
|
}
|
||||||
if callFunc == nil && len(in.metadataFile) > 0 {
|
if len(in.metadataFile) > 0 {
|
||||||
dt := make(map[string]interface{})
|
dt := make(map[string]interface{})
|
||||||
for t, r := range resp {
|
for t, r := range resp {
|
||||||
dt[t] = decodeExporterResponse(r.ExporterResponse)
|
dt[t] = decodeExporterResponse(r.ExporterResponse)
|
||||||
}
|
}
|
||||||
if warnings := printer.Warnings(); len(warnings) > 0 && confutil.MetadataWarningsEnabled() {
|
if callFunc == nil {
|
||||||
dt["buildx.build.warnings"] = warnings
|
if warnings := printer.Warnings(); len(warnings) > 0 && confutil.MetadataWarningsEnabled() {
|
||||||
|
dt["buildx.build.warnings"] = warnings
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := writeMetadataFile(in.metadataFile, dt); err != nil {
|
if err := writeMetadataFile(in.metadataFile, dt); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -367,20 +367,23 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
|
||||||
return errors.Wrap(err, "writing image ID file")
|
return errors.Wrap(err, "writing image ID file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if options.metadataFile != "" {
|
||||||
|
dt := decodeExporterResponse(resp.ExporterResponse)
|
||||||
|
if opts.PrintFunc == nil {
|
||||||
|
if warnings := printer.Warnings(); len(warnings) > 0 && confutil.MetadataWarningsEnabled() {
|
||||||
|
dt["buildx.build.warnings"] = warnings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := writeMetadataFile(options.metadataFile, dt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if opts.PrintFunc != nil {
|
if opts.PrintFunc != nil {
|
||||||
if exitcode, err := printResult(dockerCli.Out(), opts.PrintFunc, resp.ExporterResponse); err != nil {
|
if exitcode, err := printResult(dockerCli.Out(), opts.PrintFunc, resp.ExporterResponse); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if exitcode != 0 {
|
} else if exitcode != 0 {
|
||||||
os.Exit(exitcode)
|
os.Exit(exitcode)
|
||||||
}
|
}
|
||||||
} else if options.metadataFile != "" {
|
|
||||||
dt := decodeExporterResponse(resp.ExporterResponse)
|
|
||||||
if warnings := printer.Warnings(); len(warnings) > 0 && confutil.MetadataWarningsEnabled() {
|
|
||||||
dt["buildx.build.warnings"] = warnings
|
|
||||||
}
|
|
||||||
if err := writeMetadataFile(options.metadataFile, dt); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -731,9 +734,17 @@ func writeMetadataFile(filename string, dt interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeExporterResponse(exporterResponse map[string]string) map[string]interface{} {
|
func decodeExporterResponse(exporterResponse map[string]string) map[string]interface{} {
|
||||||
|
decFunc := func(k, v string) ([]byte, error) {
|
||||||
|
if k == "result.json" {
|
||||||
|
// result.json is part of metadata response for subrequests which
|
||||||
|
// is already a JSON object: https://github.com/moby/buildkit/blob/f6eb72f2f5db07ddab89ac5e2bd3939a6444f4be/frontend/dockerui/requests.go#L100-L102
|
||||||
|
return []byte(v), nil
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.DecodeString(v)
|
||||||
|
}
|
||||||
out := make(map[string]interface{})
|
out := make(map[string]interface{})
|
||||||
for k, v := range exporterResponse {
|
for k, v := range exporterResponse {
|
||||||
dt, err := base64.StdEncoding.DecodeString(v)
|
dt, err := decFunc(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out[k] = v
|
out[k] = v
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/docker/buildx/bake"
|
"github.com/docker/buildx/bake"
|
||||||
"github.com/docker/buildx/util/gitutil"
|
"github.com/docker/buildx/util/gitutil"
|
||||||
"github.com/moby/buildkit/client"
|
"github.com/moby/buildkit/client"
|
||||||
|
"github.com/moby/buildkit/frontend/subrequests/lint"
|
||||||
"github.com/moby/buildkit/identity"
|
"github.com/moby/buildkit/identity"
|
||||||
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
|
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
|
||||||
"github.com/moby/buildkit/util/contentutil"
|
"github.com/moby/buildkit/util/contentutil"
|
||||||
|
@ -56,6 +57,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
|
||||||
testListVariables,
|
testListVariables,
|
||||||
testBakeCallCheck,
|
testBakeCallCheck,
|
||||||
testBakeCallCheckFlag,
|
testBakeCallCheckFlag,
|
||||||
|
testBakeCallMetadata,
|
||||||
testBakeMultiPlatform,
|
testBakeMultiPlatform,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1214,3 +1216,61 @@ target "another" {
|
||||||
|
|
||||||
require.Len(t, warnings, 1)
|
require.Len(t, warnings, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testBakeCallMetadata(t *testing.T, sb integration.Sandbox) {
|
||||||
|
dockerfile := []byte(`
|
||||||
|
frOM busybox as base
|
||||||
|
cOpy Dockerfile .
|
||||||
|
from scratch
|
||||||
|
COPy --from=base \
|
||||||
|
/Dockerfile \
|
||||||
|
/
|
||||||
|
`)
|
||||||
|
bakefile := []byte(`
|
||||||
|
target "default" {}
|
||||||
|
`)
|
||||||
|
dir := tmpdir(
|
||||||
|
t,
|
||||||
|
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||||
|
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd := buildxCmd(
|
||||||
|
sb,
|
||||||
|
withDir(dir),
|
||||||
|
withArgs("bake", "--call", "check,format=json", "--metadata-file", filepath.Join(dir, "md.json")),
|
||||||
|
)
|
||||||
|
stdout := bytes.Buffer{}
|
||||||
|
stderr := bytes.Buffer{}
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
require.Error(t, cmd.Run(), stdout.String(), stderr.String())
|
||||||
|
|
||||||
|
var res map[string]any
|
||||||
|
require.NoError(t, json.Unmarshal(stdout.Bytes(), &res), stdout.String())
|
||||||
|
targets, ok := res["target"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
def, ok := targets["default"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
_, ok = def["build"]
|
||||||
|
require.True(t, ok)
|
||||||
|
check, ok := def["check"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
warnings, ok := check["warnings"].([]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Len(t, warnings, 3)
|
||||||
|
|
||||||
|
dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
type mdT struct {
|
||||||
|
Default struct {
|
||||||
|
BuildRef string `json:"buildx.build.ref"`
|
||||||
|
ResultJSON lint.LintResults `json:"result.json"`
|
||||||
|
} `json:"default"`
|
||||||
|
}
|
||||||
|
var md mdT
|
||||||
|
require.NoError(t, json.Unmarshal(dt, &md), dt)
|
||||||
|
require.NotEmpty(t, md.Default.BuildRef)
|
||||||
|
require.Len(t, md.Default.ResultJSON.Warnings, 3)
|
||||||
|
}
|
||||||
|
|
|
@ -1193,6 +1193,44 @@ FROM second AS binary
|
||||||
|
|
||||||
require.Equal(t, 1, len(res.Sources))
|
require.Equal(t, 1, len(res.Sources))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("check metadata", func(t *testing.T) {
|
||||||
|
dockerfile := []byte(`
|
||||||
|
frOM busybox as base
|
||||||
|
cOpy Dockerfile .
|
||||||
|
from scratch
|
||||||
|
COPy --from=base \
|
||||||
|
/Dockerfile \
|
||||||
|
/
|
||||||
|
`)
|
||||||
|
dir := tmpdir(
|
||||||
|
t,
|
||||||
|
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd := buildxCmd(sb, withArgs("build", "--call=check,format=json", "--metadata-file", filepath.Join(dir, "md.json"), dir))
|
||||||
|
stdout := bytes.Buffer{}
|
||||||
|
stderr := bytes.Buffer{}
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
require.Error(t, cmd.Run(), stdout.String(), stderr.String())
|
||||||
|
|
||||||
|
var res lint.LintResults
|
||||||
|
require.NoError(t, json.Unmarshal(stdout.Bytes(), &res), stdout.String())
|
||||||
|
require.Len(t, res.Warnings, 3)
|
||||||
|
|
||||||
|
dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
type mdT struct {
|
||||||
|
BuildRef string `json:"buildx.build.ref"`
|
||||||
|
ResultJSON lint.LintResults `json:"result.json"`
|
||||||
|
}
|
||||||
|
var md mdT
|
||||||
|
require.NoError(t, json.Unmarshal(dt, &md), dt)
|
||||||
|
require.NotEmpty(t, md.BuildRef)
|
||||||
|
require.Len(t, md.ResultJSON.Warnings, 3)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestProject(t *testing.T) string {
|
func createTestProject(t *testing.T) string {
|
||||||
|
|
Loading…
Reference in New Issue