Skip to content

Commit bd447ff

Browse files
Wait for the task to succeed before starting image push (#269)
1 parent d4cd9aa commit bd447ff

File tree

9 files changed

+185
-23
lines changed

9 files changed

+185
-23
lines changed

internal/api/client.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ func (c Client) ImagePushStatus(pushID string) (ImagePushStatusResult, error) {
552552
return result, nil
553553
}
554554

555-
func (c Client) TaskStatus(cfg TaskStatusConfig) (TaskStatusResult, error) {
555+
func (c Client) TaskKeyStatus(cfg TaskKeyStatusConfig) (TaskStatusResult, error) {
556556
endpoint := fmt.Sprintf("/mint/api/runs/%s/task_status?task_key=%s", url.PathEscape(cfg.RunID), url.PathEscape(cfg.TaskKey))
557557
result := TaskStatusResult{}
558558

@@ -576,6 +576,30 @@ func (c Client) TaskStatus(cfg TaskStatusConfig) (TaskStatusResult, error) {
576576
return result, nil
577577
}
578578

579+
func (c Client) TaskIDStatus(cfg TaskIDStatusConfig) (TaskStatusResult, error) {
580+
endpoint := fmt.Sprintf("/mint/api/tasks/%s/status", url.PathEscape(cfg.TaskID))
581+
result := TaskStatusResult{}
582+
583+
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
584+
if err != nil {
585+
return result, errors.Wrap(err, "unable to create new HTTP request")
586+
}
587+
req.Header.Set("Content-Type", "application/json")
588+
req.Header.Set("Accept", "application/json")
589+
590+
resp, err := c.RoundTrip(req)
591+
if err != nil {
592+
return result, errors.Wrap(err, "HTTP request failed")
593+
}
594+
defer resp.Body.Close()
595+
596+
if err = decodeResponseJSON(resp, &result); err != nil {
597+
return result, err
598+
}
599+
600+
return result, nil
601+
}
602+
579603
func (c Client) GetLogDownloadRequest(taskId string) (LogDownloadRequestResult, error) {
580604
endpoint := fmt.Sprintf("/mint/api/log_downloads/%s", url.PathEscape(taskId))
581605
result := LogDownloadRequestResult{}

internal/api/client_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,28 @@ func TestAPIClient_ImagePushStatus(t *testing.T) {
377377
})
378378
}
379379

380+
func TestAPIClient_TaskIDStatus(t *testing.T) {
381+
t.Run("builds the request and parses the response", func(t *testing.T) {
382+
roundTrip := func(req *http.Request) (*http.Response, error) {
383+
require.Equal(t, "/mint/api/tasks/abc123/status", req.URL.Path)
384+
require.Equal(t, http.MethodGet, req.Method)
385+
386+
body := `{"polling": {"completed": true}}`
387+
return &http.Response{
388+
Status: "200 OK",
389+
StatusCode: 200,
390+
Body: io.NopCloser(bytes.NewReader([]byte(body))),
391+
}, nil
392+
}
393+
394+
c := api.NewClientWithRoundTrip(roundTrip)
395+
396+
result, err := c.TaskIDStatus(api.TaskIDStatusConfig{TaskID: "abc123"})
397+
require.NoError(t, err)
398+
require.True(t, result.Polling.Completed)
399+
})
400+
}
401+
380402
func TestAPIClient_GetLogDownloadRequest(t *testing.T) {
381403
t.Run("builds the request and parses the response without contents", func(t *testing.T) {
382404
body := struct {

internal/api/config.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,15 @@ type ImagePushStatusResult struct {
257257
Status string `json:"status"`
258258
}
259259

260-
type TaskStatusConfig struct {
260+
type TaskKeyStatusConfig struct {
261261
RunID string
262262
TaskKey string
263263
}
264264

265+
type TaskIDStatusConfig struct {
266+
TaskID string
267+
}
268+
265269
const (
266270
TaskStatusSucceeded = "succeeded"
267271
)

internal/cli/interfaces.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ type APIClient interface {
2222
GetDefaultBase() (api.DefaultBaseResult, error)
2323
StartImagePush(cfg api.StartImagePushConfig) (api.StartImagePushResult, error)
2424
ImagePushStatus(pushID string) (api.ImagePushStatusResult, error)
25-
TaskStatus(api.TaskStatusConfig) (api.TaskStatusResult, error)
25+
TaskKeyStatus(api.TaskKeyStatusConfig) (api.TaskStatusResult, error)
26+
TaskIDStatus(api.TaskIDStatusConfig) (api.TaskStatusResult, error)
2627
GetLogDownloadRequest(taskId string) (api.LogDownloadRequestResult, error)
2728
DownloadLogs(api.LogDownloadRequestResult, ...int) ([]byte, error)
2829
}

internal/cli/service_build_image.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (s Service) BuildImage(config BuildImageConfig) error {
5252
default:
5353
}
5454

55-
result, err := s.APIClient.TaskStatus(api.TaskStatusConfig{
55+
result, err := s.APIClient.TaskKeyStatus(api.TaskKeyStatusConfig{
5656
RunID: runResult.RunId,
5757
TaskKey: config.TargetTaskKey,
5858
})

internal/cli/service_build_image_test.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestService_BuildImage(t *testing.T) {
5252
}
5353

5454
callCount := 0
55-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
55+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
5656
require.Equal(t, "run-123", cfg.RunID)
5757
require.Equal(t, "build-task", cfg.TaskKey)
5858

@@ -124,7 +124,7 @@ func TestService_BuildImage(t *testing.T) {
124124
}, nil
125125
}
126126

127-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
127+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
128128
return api.TaskStatusResult{
129129
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
130130
TaskID: "task-456",
@@ -206,7 +206,7 @@ func TestService_BuildImage(t *testing.T) {
206206
}, nil
207207
}
208208

209-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
209+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
210210
return api.TaskStatusResult{}, fmt.Errorf("failed to get task status")
211211
}
212212

@@ -236,7 +236,7 @@ func TestService_BuildImage(t *testing.T) {
236236
}, nil
237237
}
238238

239-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
239+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
240240
return api.TaskStatusResult{
241241
Status: &api.TaskStatus{Result: "failed"},
242242
Polling: api.PollingResult{
@@ -270,7 +270,7 @@ func TestService_BuildImage(t *testing.T) {
270270
}, nil
271271
}
272272

273-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
273+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
274274
return api.TaskStatusResult{
275275
Status: &api.TaskStatus{Result: "failed"},
276276
Polling: api.PollingResult{
@@ -304,7 +304,7 @@ func TestService_BuildImage(t *testing.T) {
304304
}, nil
305305
}
306306

307-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
307+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
308308
return api.TaskStatusResult{
309309
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
310310
TaskID: "task-456",
@@ -346,7 +346,7 @@ func TestService_BuildImage(t *testing.T) {
346346
}, nil
347347
}
348348

349-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
349+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
350350
return api.TaskStatusResult{
351351
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
352352
TaskID: "task-456",
@@ -394,7 +394,7 @@ func TestService_BuildImage(t *testing.T) {
394394
}, nil
395395
}
396396

397-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
397+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
398398
return api.TaskStatusResult{
399399
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
400400
TaskID: "task-456",
@@ -444,7 +444,7 @@ func TestService_BuildImage(t *testing.T) {
444444
}, nil
445445
}
446446

447-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
447+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
448448
return api.TaskStatusResult{
449449
Status: &api.TaskStatus{Result: "unknown-status"},
450450
Polling: api.PollingResult{
@@ -478,7 +478,7 @@ func TestService_BuildImage(t *testing.T) {
478478
}, nil
479479
}
480480

481-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
481+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
482482
return api.TaskStatusResult{
483483
Status: nil,
484484
Polling: api.PollingResult{
@@ -512,7 +512,7 @@ func TestService_BuildImage(t *testing.T) {
512512
}, nil
513513
}
514514

515-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
515+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
516516
return api.TaskStatusResult{
517517
Status: &api.TaskStatus{Result: "pending"},
518518
Polling: api.PollingResult{
@@ -548,7 +548,7 @@ func TestService_BuildImage(t *testing.T) {
548548
}, nil
549549
}
550550

551-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
551+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
552552
return api.TaskStatusResult{
553553
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
554554
TaskID: "task-456",
@@ -609,7 +609,7 @@ func TestService_BuildImage(t *testing.T) {
609609
}, nil
610610
}
611611

612-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
612+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
613613
return api.TaskStatusResult{
614614
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
615615
TaskID: "task-456",
@@ -632,6 +632,14 @@ func TestService_BuildImage(t *testing.T) {
632632
return types.AuthConfig{Username: "registry-user", Password: "registry-pass"}, nil
633633
}
634634

635+
s.mockAPI.MockTaskIDStatus = func(cfg api.TaskIDStatusConfig) (api.TaskStatusResult, error) {
636+
return api.TaskStatusResult{
637+
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
638+
TaskID: "task-456",
639+
Polling: api.PollingResult{Completed: true},
640+
}, nil
641+
}
642+
635643
s.mockAPI.MockStartImagePush = func(cfg api.StartImagePushConfig) (api.StartImagePushResult, error) {
636644
require.Equal(t, "task-456", cfg.TaskID)
637645
require.Equal(t, "registry.com", cfg.Image.Registry)
@@ -679,7 +687,7 @@ func TestService_BuildImage(t *testing.T) {
679687
}, nil
680688
}
681689

682-
s.mockAPI.MockTaskStatus = func(cfg api.TaskStatusConfig) (api.TaskStatusResult, error) {
690+
s.mockAPI.MockTaskKeyStatus = func(cfg api.TaskKeyStatusConfig) (api.TaskStatusResult, error) {
683691
return api.TaskStatusResult{
684692
Status: &api.TaskStatus{Result: api.TaskStatusSucceeded},
685693
TaskID: "task-456",

internal/cli/service_push_image.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"io"
@@ -92,6 +93,36 @@ func (s Service) PushImage(config PushImageConfig) error {
9293
)
9394
}
9495

96+
taskStatusTimeout, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
97+
defer cancel()
98+
99+
succeeded := false
100+
for !succeeded {
101+
select {
102+
case <-taskStatusTimeout.Done():
103+
stopStartSpinner()
104+
return fmt.Errorf("timed out waiting for task %s to complete", config.TaskID)
105+
default:
106+
}
107+
108+
result, err := s.APIClient.TaskIDStatus(api.TaskIDStatusConfig{TaskID: config.TaskID})
109+
if err != nil {
110+
stopStartSpinner()
111+
return fmt.Errorf("failed to get task status: %w", err)
112+
}
113+
114+
if result.Polling.Completed {
115+
if result.Status != nil && result.Status.Result == api.TaskStatusSucceeded {
116+
succeeded = true
117+
} else {
118+
stopStartSpinner()
119+
return fmt.Errorf("task failed")
120+
}
121+
} else {
122+
time.Sleep(time.Duration(*result.Polling.BackoffMs) * time.Millisecond)
123+
}
124+
}
125+
95126
result, err := s.APIClient.StartImagePush(request)
96127
stopStartSpinner()
97128
if err != nil {

0 commit comments

Comments
 (0)