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:
@@ -271,6 +271,8 @@ func TestPerformBuildUsesBuildKit(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.URL.Path, "/version"):
|
||||
_, _ = w.Write([]byte(`{"Version":"27.3.1","ApiVersion":"1.47"}`))
|
||||
case strings.HasSuffix(r.URL.Path, "/build"):
|
||||
if r.URL.Query().Get("version") != "2" {
|
||||
http.Error(w, "not a BuildKit build", http.StatusBadRequest)
|
||||
@@ -314,3 +316,82 @@ func TestPerformBuildUsesBuildKit(t *testing.T) {
|
||||
t.Errorf("build log is missing the build step:\n%s", buildLog.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestPerformBuildFails runs builds that fail against a fake Docker API and
|
||||
// checks that each returns its own error and that no image is inspected
|
||||
// afterwards.
|
||||
func TestPerformBuildFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
engine string // Docker Engine version the fake daemon reports
|
||||
apiVersion string // API version the fake daemon reports
|
||||
buildOutput string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "build step fails",
|
||||
engine: "27.3.1",
|
||||
apiVersion: "1.47",
|
||||
buildOutput: `{"stream":"Step 1/1 : RUN false\n"}` + "\n" +
|
||||
`{"errorDetail":{"message":"exit code: 1"},"error":"exit code: 1"}`,
|
||||
wantErr: "exit code: 1",
|
||||
},
|
||||
{
|
||||
name: "daemon too old for BuildKit",
|
||||
engine: "18.06.3-ce",
|
||||
apiVersion: "1.38",
|
||||
wantErr: "BuildKit is unavailable on the Docker daemon: " +
|
||||
"Docker Engine 18.06.3-ce (API 1.38) is older than 18.09 (API 1.39); " +
|
||||
"upgrade Docker Engine",
|
||||
},
|
||||
{
|
||||
// The build step's own error shows the build went ahead.
|
||||
name: "daemon at API 1.39 builds",
|
||||
engine: "18.09.9",
|
||||
apiVersion: "1.39",
|
||||
buildOutput: `{"stream":"Step 1/1 : RUN false\n"}` + "\n" +
|
||||
`{"errorDetail":{"message":"exit code: 1"},"error":"exit code: 1"}`,
|
||||
wantErr: "exit code: 1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.URL.Path, "/version"):
|
||||
_, _ = fmt.Fprintf(w, `{"Version":%q,"ApiVersion":%q}`,
|
||||
tt.engine, tt.apiVersion)
|
||||
case strings.HasSuffix(r.URL.Path, "/build"):
|
||||
_, _ = w.Write([]byte(tt.buildOutput))
|
||||
default:
|
||||
t.Errorf("unexpected request to %s", r.URL.Path)
|
||||
}
|
||||
},
|
||||
))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
dockerAPI, err := client.NewClientWithOpts(
|
||||
client.WithHost("tcp://" + srv.Listener.Addr().String()),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := &Client{docker: dockerAPI, log: slog.Default()}
|
||||
|
||||
_, err = c.performBuild(t.Context(), BuildImageOptions{
|
||||
ContextDir: t.TempDir(),
|
||||
Tags: []string{"upaas-test:1"},
|
||||
})
|
||||
if err == nil || err.Error() != tt.wantErr {
|
||||
t.Errorf("got error %v, want %q", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user