build: opt to set progress warnings in response

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2024-06-24 16:38:09 +02:00 committed by CrazyMax
parent e5ded4b2de
commit f7bcafed21
No known key found for this signature in database
GPG Key ID: ADE44D8C9D44FBE4
9 changed files with 199 additions and 31 deletions

View File

@ -84,6 +84,8 @@ jobs:
endpoint: tcp://localhost:1234 endpoint: tcp://localhost:1234
- driver: docker-container - driver: docker-container
metadata-provenance: max metadata-provenance: max
- driver: docker-container
metadata-warnings: true
exclude: exclude:
- driver: docker - driver: docker
multi-node: mnode-true multi-node: mnode-true
@ -134,6 +136,9 @@ jobs:
if [ -n "${{ matrix.metadata-provenance }}" ]; then if [ -n "${{ matrix.metadata-provenance }}" ]; then
echo "BUILDX_METADATA_PROVENANCE=${{ matrix.metadata-provenance }}" >> $GITHUB_ENV echo "BUILDX_METADATA_PROVENANCE=${{ matrix.metadata-provenance }}" >> $GITHUB_ENV
fi fi
if [ -n "${{ matrix.metadata-warnings }}" ]; then
echo "BUILDX_METADATA_WARNINGS=${{ matrix.metadata-warnings }}" >> $GITHUB_ENV
fi
- -
name: Install k3s name: Install k3s
if: matrix.driver == 'kubernetes' if: matrix.driver == 'kubernetes'

View File

@ -22,6 +22,7 @@ import (
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/docker/buildx/util/tracing" "github.com/docker/buildx/util/tracing"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/identity" "github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/progress/progressui" "github.com/moby/buildkit/util/progress/progressui"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -130,15 +131,30 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
return err return err
} }
var resp map[string]*client.SolveResponse
defer func() { defer func() {
if printer != nil { if printer != nil {
err1 := printer.Wait() err1 := printer.Wait()
if err == nil { if err == nil {
err = err1 err = err1
} }
if err == nil && progressMode != progressui.QuietMode && progressMode != progressui.RawJSONMode { if err != nil {
return
}
if progressMode != progressui.QuietMode && progressMode != progressui.RawJSONMode {
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term) desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
} }
if resp != nil && len(in.metadataFile) > 0 {
dt := make(map[string]interface{})
for t, r := range resp {
dt[t] = decodeExporterResponse(r.ExporterResponse)
}
if warnings := printer.Warnings(); len(warnings) > 0 && confutil.MetadataWarningsEnabled() {
dt["buildx.build.warnings"] = warnings
}
err = writeMetadataFile(in.metadataFile, dt)
}
} }
}() }()
@ -229,22 +245,12 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
return err return err
} }
resp, err := build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), printer) resp, err = build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), printer)
if err != nil { if err != nil {
return wrapBuildError(err, true) return wrapBuildError(err, true)
} }
if len(in.metadataFile) > 0 { return
dt := make(map[string]interface{})
for t, r := range resp {
dt[t] = decodeExporterResponse(r.ExporterResponse)
}
if err := writeMetadataFile(in.metadataFile, dt); err != nil {
return err
}
}
return err
} }
func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {

View File

@ -374,7 +374,11 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
return err return err
} }
} else if options.metadataFile != "" { } else if options.metadataFile != "" {
if err := writeMetadataFile(options.metadataFile, decodeExporterResponse(resp.ExporterResponse)); err != nil { 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 err
} }
} }

View File

@ -119,6 +119,7 @@ $ cat metadata.json
```json ```json
{ {
"buildx.build.warnings": {},
"db": { "db": {
"buildx.build.provenance": {}, "buildx.build.provenance": {},
"buildx.build.ref": "mybuilder/mybuilder0/0fjb6ubs52xx3vygf6fgdl611", "buildx.build.ref": "mybuilder/mybuilder0/0fjb6ubs52xx3vygf6fgdl611",
@ -161,6 +162,12 @@ $ cat metadata.json
> * `max` sets full provenance. > * `max` sets full provenance.
> * `disabled`, `false` or `0` does not set any provenance. > * `disabled`, `false` or `0` does not set any provenance.
> **Note**
>
> Build warnings (`buildx.build.warnings`) are not included by default. Set the
> `BUILDX_METADATA_WARNINGS` environment variable to `1` or `true` to
> include them.
### <a name="no-cache"></a> Don't use cache when building the image (--no-cache) ### <a name="no-cache"></a> Don't use cache when building the image (--no-cache)
Same as `build --no-cache`. Don't use cache when building the image. Same as `build --no-cache`. Don't use cache when building the image.

View File

@ -330,6 +330,7 @@ $ cat metadata.json
{ {
"buildx.build.provenance": {}, "buildx.build.provenance": {},
"buildx.build.ref": "mybuilder/mybuilder0/0fjb6ubs52xx3vygf6fgdl611", "buildx.build.ref": "mybuilder/mybuilder0/0fjb6ubs52xx3vygf6fgdl611",
"buildx.build.warnings": {},
"containerimage.config.digest": "sha256:2937f66a9722f7f4a2df583de2f8cb97fc9196059a410e7f00072fc918930e66", "containerimage.config.digest": "sha256:2937f66a9722f7f4a2df583de2f8cb97fc9196059a410e7f00072fc918930e66",
"containerimage.descriptor": { "containerimage.descriptor": {
"annotations": { "annotations": {
@ -353,6 +354,12 @@ $ cat metadata.json
> * `max` sets full provenance. > * `max` sets full provenance.
> * `disabled`, `false` or `0` does not set any provenance. > * `disabled`, `false` or `0` does not set any provenance.
> **Note**
>
> Build warnings (`buildx.build.warnings`) are not included by default. Set the
> `BUILDX_METADATA_WARNINGS` environment variable to `1` or `true` to
> include them.
### <a name="no-cache-filter"></a> Ignore build cache for specific stages (--no-cache-filter) ### <a name="no-cache-filter"></a> Ignore build cache for specific stages (--no-cache-filter)
The `--no-cache-filter` lets you specify one or more stages of a multi-stage The `--no-cache-filter` lets you specify one or more stages of a multi-stage

View File

@ -109,21 +109,21 @@ buildxCmd inspect --bootstrap --builder="${builderName}"
# create dockerfile # create dockerfile
cat > "${dockerfile}" <<EOL cat > "${dockerfile}" <<EOL
FROM busybox as build fRom busybox as build
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG BUILDPLATFORM ARG BUILDPLATFORM
RUN echo "I am running on \$BUILDPLATFORM, building for \$TARGETPLATFORM" > /log RUN echo "I am running on \$BUILDPLATFORM, building for \$TARGETPLATFORM" > /log
FROM busybox AS log FROM busybox As log
COPY --from=build /log /log COPY --from=build /log /log
RUN cat /log RUN cat /log
RUN uname -a RUN uname -a
FROM busybox AS hello FROm busybox AS hello
RUN echo hello > /hello RUN echo hello > /hello
FROM scratch FROM scratch
COPY --from=log /log /log CoPY --from=log /log /log
COPY --from=hello /hello /hello COPY --from=hello /hello /hello
EOL EOL

View File

@ -9,6 +9,7 @@ import (
"github.com/containerd/continuity/fs/fstest" "github.com/containerd/continuity/fs/fstest"
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
"github.com/moby/buildkit/client"
"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"
@ -42,7 +43,8 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakeEmpty, testBakeEmpty,
testBakeShmSize, testBakeShmSize,
testBakeUlimits, testBakeUlimits,
testBakeMetadata, testBakeMetadataProvenance,
testBakeMetadataWarnings,
testBakeMultiExporters, testBakeMultiExporters,
testBakeLoadPush, testBakeLoadPush,
} }
@ -633,19 +635,22 @@ target "default" {
require.Contains(t, string(dt), `1024`) require.Contains(t, string(dt), `1024`)
} }
func testBakeMetadata(t *testing.T, sb integration.Sandbox) { func testBakeMetadataProvenance(t *testing.T, sb integration.Sandbox) {
t.Run("default", func(t *testing.T) {
bakeMetadataProvenance(t, sb, "")
})
t.Run("max", func(t *testing.T) { t.Run("max", func(t *testing.T) {
bakeMetadata(t, sb, "max") bakeMetadataProvenance(t, sb, "max")
}) })
t.Run("min", func(t *testing.T) { t.Run("min", func(t *testing.T) {
bakeMetadata(t, sb, "min") bakeMetadataProvenance(t, sb, "min")
}) })
t.Run("disabled", func(t *testing.T) { t.Run("disabled", func(t *testing.T) {
bakeMetadata(t, sb, "disabled") bakeMetadataProvenance(t, sb, "disabled")
}) })
} }
func bakeMetadata(t *testing.T, sb integration.Sandbox, metadataMode string) { func bakeMetadataProvenance(t *testing.T, sb integration.Sandbox, metadataMode string) {
dockerfile := []byte(` dockerfile := []byte(`
FROM scratch FROM scratch
COPY foo /foo COPY foo /foo
@ -676,7 +681,7 @@ target "default" {
withEnv("BUILDX_METADATA_PROVENANCE="+metadataMode), withEnv("BUILDX_METADATA_PROVENANCE="+metadataMode),
) )
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
require.NoError(t, err, out) require.NoError(t, err, string(out))
dt, err := os.ReadFile(filepath.Join(dirDest, "md.json")) dt, err := os.ReadFile(filepath.Join(dirDest, "md.json"))
require.NoError(t, err) require.NoError(t, err)
@ -706,6 +711,71 @@ target "default" {
require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType) require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType)
} }
func testBakeMetadataWarnings(t *testing.T, sb integration.Sandbox) {
t.Run("default", func(t *testing.T) {
bakeMetadataWarnings(t, sb, "")
})
t.Run("true", func(t *testing.T) {
bakeMetadataWarnings(t, sb, "true")
})
t.Run("false", func(t *testing.T) {
bakeMetadataWarnings(t, sb, "false")
})
}
func bakeMetadataWarnings(t *testing.T, sb integration.Sandbox, mode string) {
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),
)
dirDest := t.TempDir()
cmd := buildxCmd(
sb,
withDir(dir),
withArgs("bake", "--metadata-file", filepath.Join(dirDest, "md.json"), "--set", "*.output=type=cacheonly"),
withEnv("BUILDX_METADATA_WARNINGS="+mode),
)
out, err := cmd.CombinedOutput()
require.NoError(t, err, string(out))
dt, err := os.ReadFile(filepath.Join(dirDest, "md.json"))
require.NoError(t, err)
type mdT struct {
BuildWarnings []client.VertexWarning `json:"buildx.build.warnings"`
Default struct {
BuildRef string `json:"buildx.build.ref"`
} `json:"default"`
}
var md mdT
err = json.Unmarshal(dt, &md)
require.NoError(t, err, string(dt))
require.NotEmpty(t, md.Default.BuildRef, string(dt))
if mode == "" || mode == "false" {
require.Empty(t, md.BuildWarnings, string(dt))
return
}
skipNoCompatBuildKit(t, sb, ">= 0.14.0-0", "lint")
require.Len(t, md.BuildWarnings, 3, string(dt))
}
func testBakeMultiExporters(t *testing.T, sb integration.Sandbox) { func testBakeMultiExporters(t *testing.T, sb integration.Sandbox) {
if !isDockerContainerWorker(sb) { if !isDockerContainerWorker(sb) {
t.Skip("only testing with docker-container worker") t.Skip("only testing with docker-container worker")

View File

@ -16,6 +16,7 @@ import (
"github.com/containerd/containerd/platforms" "github.com/containerd/containerd/platforms"
"github.com/containerd/continuity/fs/fstest" "github.com/containerd/continuity/fs/fstest"
"github.com/creack/pty" "github.com/creack/pty"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/frontend/subrequests/lint" "github.com/moby/buildkit/frontend/subrequests/lint"
"github.com/moby/buildkit/frontend/subrequests/outline" "github.com/moby/buildkit/frontend/subrequests/outline"
"github.com/moby/buildkit/frontend/subrequests/targets" "github.com/moby/buildkit/frontend/subrequests/targets"
@ -59,7 +60,8 @@ var buildTests = []func(t *testing.T, sb integration.Sandbox){
testBuildNetworkModeBridge, testBuildNetworkModeBridge,
testBuildShmSize, testBuildShmSize,
testBuildUlimit, testBuildUlimit,
testBuildMetadata, testBuildMetadataProvenance,
testBuildMetadataWarnings,
testBuildMultiExporters, testBuildMultiExporters,
testBuildLoadPush, testBuildLoadPush,
testBuildSecret, testBuildSecret,
@ -560,19 +562,22 @@ COPY --from=build /ulimit /
require.Contains(t, string(dt), `1024`) require.Contains(t, string(dt), `1024`)
} }
func testBuildMetadata(t *testing.T, sb integration.Sandbox) { func testBuildMetadataProvenance(t *testing.T, sb integration.Sandbox) {
t.Run("default", func(t *testing.T) {
buildMetadataProvenance(t, sb, "")
})
t.Run("max", func(t *testing.T) { t.Run("max", func(t *testing.T) {
buildMetadata(t, sb, "max") buildMetadataProvenance(t, sb, "max")
}) })
t.Run("min", func(t *testing.T) { t.Run("min", func(t *testing.T) {
buildMetadata(t, sb, "min") buildMetadataProvenance(t, sb, "min")
}) })
t.Run("disabled", func(t *testing.T) { t.Run("disabled", func(t *testing.T) {
buildMetadata(t, sb, "disabled") buildMetadataProvenance(t, sb, "disabled")
}) })
} }
func buildMetadata(t *testing.T, sb integration.Sandbox, metadataMode string) { func buildMetadataProvenance(t *testing.T, sb integration.Sandbox, metadataMode string) {
dir := createTestProject(t) dir := createTestProject(t)
dirDest := t.TempDir() dirDest := t.TempDir()
@ -616,6 +621,61 @@ func buildMetadata(t *testing.T, sb integration.Sandbox, metadataMode string) {
require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType) require.Equal(t, provenancetypes.BuildKitBuildType, prv.BuildType)
} }
func testBuildMetadataWarnings(t *testing.T, sb integration.Sandbox) {
t.Run("default", func(t *testing.T) {
buildMetadataWarnings(t, sb, "")
})
t.Run("true", func(t *testing.T) {
buildMetadataWarnings(t, sb, "true")
})
t.Run("false", func(t *testing.T) {
buildMetadataWarnings(t, sb, "false")
})
}
func buildMetadataWarnings(t *testing.T, sb integration.Sandbox, mode string) {
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", "--metadata-file", filepath.Join(dir, "md.json"), dir),
withEnv("BUILDX_METADATA_WARNINGS="+mode),
)
out, err := cmd.CombinedOutput()
require.NoError(t, err, string(out))
dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
require.NoError(t, err)
type mdT struct {
BuildRef string `json:"buildx.build.ref"`
BuildWarnings []client.VertexWarning `json:"buildx.build.warnings"`
}
var md mdT
err = json.Unmarshal(dt, &md)
require.NoError(t, err, string(dt))
require.NotEmpty(t, md.BuildRef, string(dt))
if mode == "" || mode == "false" {
require.Empty(t, md.BuildWarnings, string(dt))
return
}
skipNoCompatBuildKit(t, sb, ">= 0.14.0-0", "lint")
require.Len(t, md.BuildWarnings, 3, string(dt))
}
func testBuildMultiExporters(t *testing.T, sb integration.Sandbox) { func testBuildMultiExporters(t *testing.T, sb integration.Sandbox) {
if !isDockerContainerWorker(sb) { if !isDockerContainerWorker(sb) {
t.Skip("only testing with docker-container worker") t.Skip("only testing with docker-container worker")

View File

@ -39,3 +39,12 @@ func ParseMetadataProvenance(inp string) MetadataProvenanceMode {
} }
return MetadataProvenanceModeMin return MetadataProvenanceModeMin
} }
// MetadataWarningsEnabled returns whether metadata warnings are enabled from
// BUILDX_METADATA_WARNINGS environment variable (default false)
func MetadataWarningsEnabled() bool {
if ok, err := strconv.ParseBool(os.Getenv("BUILDX_METADATA_WARNINGS")); err == nil {
return ok
}
return false
}