Skip to content
This repository has been archived by the owner on Jul 4, 2024. It is now read-only.

Commit

Permalink
feat: retry deployments (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
johanneswuerbach authored Mar 27, 2023
2 parents 51f1d26 + cd7a699 commit f084be7
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 9 deletions.
1 change: 1 addition & 0 deletions internal/command/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ var (
envID string

deploy bool
retry bool
verbose bool
)
3 changes: 2 additions & 1 deletion internal/command/delta.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func init() {
deltaCmd.MarkFlagRequired("env")

deltaCmd.Flags().BoolVar(&deploy, "deploy", false, "Trigger a new delta deployment at the end")
deltaCmd.Flags().BoolVar(&retry, "retry", false, "Retry deployments when a deployment is currently in progress")
deltaCmd.Flags().BoolVar(&verbose, "verbose", false, "Enable diagnostic messages (written to STDERR)")

rootCmd.AddCommand(deltaCmd)
Expand Down Expand Up @@ -94,7 +95,7 @@ func delta(cmd *cobra.Command, args []string) error {
//
if deploy {
log.Printf("Starting a new deployment for delta '%s'...\n", res.ID)
_, err := client.StartDeployment(context.Background(), orgID, appID, envID, &ht.StartDeploymentRequest{
_, err := client.StartDeployment(context.Background(), orgID, appID, envID, retry, &ht.StartDeploymentRequest{
DeltaID: res.ID,
Comment: "Auto-deployment (SCORE)",
})
Expand Down
14 changes: 13 additions & 1 deletion internal/humanitec_go/client/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ import (
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/sendgrid/rest"

humanitec "github.com/score-spec/score-humanitec/internal/humanitec_go/types"
)

var (
retryDelay = 5 * time.Second
)

// StartDeployment starts a new Deployment.
func (api *apiClient) StartDeployment(ctx context.Context, orgID, appID, envID string, deployment *humanitec.StartDeploymentRequest) (*humanitec.Deployment, error) {
func (api *apiClient) StartDeployment(ctx context.Context, orgID, appID, envID string, retry bool, deployment *humanitec.StartDeploymentRequest) (*humanitec.Deployment, error) {
data, err := json.Marshal(deployment)
if err != nil {
return nil, fmt.Errorf("marshalling payload into JSON: %w", err)
Expand Down Expand Up @@ -53,6 +58,13 @@ func (api *apiClient) StartDeployment(ctx context.Context, orgID, appID, envID s
return &res, nil
}

case http.StatusConflict:
if retry {
time.Sleep(retryDelay)
return api.StartDeployment(ctx, orgID, appID, envID, retry, deployment)
}

fallthrough
default:
return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode))
}
Expand Down
57 changes: 51 additions & 6 deletions internal/humanitec_go/client/deployments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ func TestStartDeployment(t *testing.T) {
Name string
ApiUrl string
Data *humanitec.StartDeploymentRequest
StatusCode int
Retry bool
StatusCode []int
Response []byte
ExpectedResult *humanitec.Deployment
ExpectedError error
Expand All @@ -47,7 +48,7 @@ func TestStartDeployment(t *testing.T) {
DeltaID: "test-delta",
Comment: "Test deployment",
},
StatusCode: http.StatusCreated,
StatusCode: []int{http.StatusCreated},
Response: []byte(`{
"id": "qwe...rty",
"env_id": "test-env",
Expand Down Expand Up @@ -81,19 +82,61 @@ func TestStartDeployment(t *testing.T) {
},
{
Name: "Should handle API errors",
StatusCode: http.StatusInternalServerError,
StatusCode: []int{http.StatusInternalServerError},
ExpectedError: errors.New("HTTP 500"),
},
{
Name: "Should handle response parsing errors",
StatusCode: http.StatusOK,
StatusCode: []int{http.StatusOK},
Response: []byte(`{NOT A VALID JSON}`),
ExpectedError: errors.New("parsing response"),
},
{
Name: "Should return conflict errors without retry",
Data: &humanitec.StartDeploymentRequest{
DeltaID: "test-delta",
Comment: "Test deployment",
},
Retry: false,
StatusCode: []int{http.StatusConflict},
ExpectedError: errors.New("HTTP 409"),
},
{
Name: "Should retry conflict errors with retry",
Data: &humanitec.StartDeploymentRequest{
DeltaID: "test-delta",
Comment: "Test deployment",
},
Retry: true,
StatusCode: []int{http.StatusConflict, http.StatusCreated},
Response: []byte(`{
"id": "qwe...rty",
"env_id": "test-env",
"from_id": "qwe...rty",
"delta_id": "test-delta",
"comment": "Test deployment",
"status": "in progress",
"status_changed_at": "2020-05-22T14:59:01Z",
"created_at": "2020-05-22T14:58:07Z",
"created_by": "a.user@example.com"
}`),
ExpectedResult: &humanitec.Deployment{
ID: "qwe...rty",
EnvID: "test-env",
FromID: "qwe...rty",
DeltaID: "test-delta",
Comment: "Test deployment",
Status: "in progress",
StatusChangedAt: time.Time{},
CreatedBy: "a.user@example.com",
CreatedAt: time.Time{},
},
},
}

for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
request := 0
fakeServer := httptest.NewServer(
http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -114,11 +157,13 @@ func TestStartDeployment(t *testing.T) {
assert.Equal(t, tt.Data, &body)
}

w.WriteHeader(tt.StatusCode)
w.WriteHeader(tt.StatusCode[request])
if len(tt.Response) > 0 {
w.Header().Set("Content-Type", "application/json")
w.Write(tt.Response)
}

request++
return
}

Expand All @@ -134,7 +179,7 @@ func TestStartDeployment(t *testing.T) {

client, err := NewClient(tt.ApiUrl, apiToken, fakeServer.Client())
assert.NoError(t, err)
res, err := client.StartDeployment(testutil.TestContext(), orgID, appID, envID, tt.Data)
res, err := client.StartDeployment(testutil.TestContext(), orgID, appID, envID, tt.Retry, tt.Data)

if tt.ExpectedError != nil {
// On Error
Expand Down
2 changes: 1 addition & 1 deletion internal/humanitec_go/client/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ type Client interface {

// Deployments
//
StartDeployment(ctx context.Context, orgID, appID, envID string, deployment *humanitec.StartDeploymentRequest) (*humanitec.Deployment, error)
StartDeployment(ctx context.Context, orgID, appID, envID string, retry bool, deployment *humanitec.StartDeploymentRequest) (*humanitec.Deployment, error)
}

0 comments on commit f084be7

Please sign in to comment.