Report the build's own error and refuse daemons too old for BuildKit (closes #234)
Check / check (pull_request) Successful in 4m23s
Check / check (pull_request) Successful in 4m23s
A build whose output ends in Docker's error line now fails with that error, instead of going on to inspect a tag that was never created. The build output is written to the deployment log before the failure is recorded, so the log ends in order. Before building, upaas compares the daemon's API version with 1.39 (Docker Engine 18.09), the first that builds with BuildKit without experimental mode, and fails the deploy on an older daemon instead of letting it use the legacy builder. The README's Compose section gives the update command and the Docker Engine versions builds need. Disclosure: merged after a rebase that changed only TODO.md; the review gated this tree on the current next. Model: opus-5-5 Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
This commit was merged in pull request #245.
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
@@ -61,6 +62,15 @@ var ErrInvalidBranch = errors.New("invalid branch name")
|
||||
// ErrInvalidCommitSHA is returned when a commit SHA is not a valid hex string.
|
||||
var ErrInvalidCommitSHA = errors.New("invalid commit SHA")
|
||||
|
||||
// ErrBuildKitUnavailable is returned when the Docker daemon is too old to
|
||||
// build with BuildKit.
|
||||
var ErrBuildKitUnavailable = errors.New("BuildKit is unavailable on the Docker daemon")
|
||||
|
||||
// minBuildKitAPIVersion is the API version of Docker Engine 18.09, the first
|
||||
// that builds with BuildKit when asked to without experimental mode. Older
|
||||
// daemons refuse the request or silently use the legacy builder.
|
||||
const minBuildKitAPIVersion = "1.39"
|
||||
|
||||
// validBranchRe matches safe git branch names.
|
||||
var validBranchRe = regexp.MustCompile(`^[a-zA-Z0-9._/\-]+$`)
|
||||
|
||||
@@ -595,6 +605,20 @@ func (c *Client) performBuild(
|
||||
ctx context.Context,
|
||||
opts BuildImageOptions,
|
||||
) (ImageID, error) {
|
||||
server, err := c.docker.ServerVersion(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get Docker version: %w", err)
|
||||
}
|
||||
|
||||
if versions.LessThan(server.APIVersion, minBuildKitAPIVersion) {
|
||||
return "", fmt.Errorf(
|
||||
"%w: Docker Engine %s (API %s) is older than 18.09 (API %s); "+
|
||||
"upgrade Docker Engine",
|
||||
ErrBuildKitUnavailable, server.Version, server.APIVersion,
|
||||
minBuildKitAPIVersion,
|
||||
)
|
||||
}
|
||||
|
||||
// Create tar archive of build context
|
||||
tarArchive, err := archive.TarWithOptions(opts.ContextDir, &archive.TarOptions{})
|
||||
if err != nil {
|
||||
@@ -660,7 +684,8 @@ const scannerMaxBufferSize = 1024 * 1024 // 1MB
|
||||
// newline-delimited JSON. BuildKit's progress arrives encoded in
|
||||
// "moby.buildkit.trace" messages; these are decoded and written as plain
|
||||
// text, as "docker build --progress=plain" shows it. Other lines, such as
|
||||
// build errors, are written unchanged.
|
||||
// build errors, are written unchanged. Docker ends a failed build with a line
|
||||
// carrying the error; it is returned once the output is written.
|
||||
func (c *Client) streamBuildOutput(
|
||||
ctx context.Context,
|
||||
body io.Reader,
|
||||
@@ -690,6 +715,8 @@ func (c *Client) streamBuildOutput(
|
||||
buf := make([]byte, 0, scannerInitialBufferSize)
|
||||
scanner.Buffer(buf, scannerMaxBufferSize)
|
||||
|
||||
var buildErr error
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Bytes()
|
||||
|
||||
@@ -708,6 +735,10 @@ func (c *Client) streamBuildOutput(
|
||||
continue
|
||||
}
|
||||
|
||||
if err == nil && msg.Error != nil {
|
||||
buildErr = msg.Error
|
||||
}
|
||||
|
||||
// One write per line, so it is not split by the display's output.
|
||||
_, _ = fmt.Fprintf(out, "%s\n", line)
|
||||
}
|
||||
@@ -720,7 +751,7 @@ func (c *Client) streamBuildOutput(
|
||||
return fmt.Errorf("failed to read build output: %w", scanErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
return buildErr
|
||||
}
|
||||
|
||||
func (c *Client) performClone(
|
||||
|
||||
Reference in New Issue
Block a user