diff --git a/internal/command/delta.go b/internal/command/delta.go index b9ee701..6c7457d 100644 --- a/internal/command/delta.go +++ b/internal/command/delta.go @@ -15,6 +15,7 @@ import ( "net/http" "os" "path/filepath" + "regexp" "github.com/score-spec/score-humanitec/internal/humanitec" api "github.com/score-spec/score-humanitec/internal/humanitec_go/client" @@ -74,6 +75,11 @@ func delta(cmd *cobra.Command, args []string) error { return err } + // Validate the ID + if err := validateIDs(); err != nil { + return err + } + // Prepare a new deployment // log.Print("Preparing a new deployment...\n") @@ -124,3 +130,22 @@ func delta(cmd *cobra.Command, args []string) error { return nil } + +var validID = regexp.MustCompile(`^[a-z0-9](?:-?[a-z0-9]+)+$`) + +func validateIDs() error { + ids := []struct { + name string + id string + }{ + {"organization", orgID}, {"application", appID}, {"environment", envID}, + } + + for _, e := range ids { + if !validID.MatchString(e.id) { + return fmt.Errorf("invalid %s id '%s'. Did you use the %s name instead of the id?", e.name, e.id, e.name) + } + } + + return nil +} diff --git a/internal/humanitec_go/client/deltas.go b/internal/humanitec_go/client/deltas.go index 29703b5..6632554 100644 --- a/internal/humanitec_go/client/deltas.go +++ b/internal/humanitec_go/client/deltas.go @@ -57,7 +57,7 @@ func (api *apiClient) CreateDelta(ctx context.Context, orgID, appID string, delt } default: - return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode)) + return nil, resError(req, resp) } } @@ -100,6 +100,10 @@ func (api *apiClient) UpdateDelta(ctx context.Context, orgID string, appID strin return &res, nil } default: - return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode)) + return nil, resError(req, resp) } } + +func resError(req rest.Request, resp *rest.Response) error { + return fmt.Errorf("humanitec api: %s %s: unexpected response status %d - %s\n%s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode), resp.Body) +} diff --git a/internal/humanitec_go/client/deltas_test.go b/internal/humanitec_go/client/deltas_test.go index 1df7870..145878c 100644 --- a/internal/humanitec_go/client/deltas_test.go +++ b/internal/humanitec_go/client/deltas_test.go @@ -87,7 +87,8 @@ func TestCreateDelta(t *testing.T) { { Name: "Should handle API errors", StatusCode: http.StatusInternalServerError, - ExpectedError: errors.New("HTTP 500"), + ExpectedError: errors.New("unexpected response status 500 - Internal Server Error\nerror details"), + Response: []byte(`error details`), }, { Name: "Should handle response parsing errors", @@ -208,6 +209,7 @@ func TestUpdateDelta_fail(t *testing.T) { http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) + w.Write([]byte("{\"error\": \"Not Found\"}")) }, ), ) @@ -219,5 +221,5 @@ func TestUpdateDelta_fail(t *testing.T) { {Modules: humanitec.ModuleDeltas{}}, }) assert.Nil(t, res) - assert.ErrorContains(t, err, ": HTTP 404 - Not Found") + assert.ErrorContains(t, err, ": unexpected response status 404 - Not Found\n{\"error\": \"Not Found\"}") } diff --git a/internal/humanitec_go/client/deployments.go b/internal/humanitec_go/client/deployments.go index 812afb5..c5b991c 100644 --- a/internal/humanitec_go/client/deployments.go +++ b/internal/humanitec_go/client/deployments.go @@ -67,6 +67,6 @@ func (api *apiClient) StartDeployment(ctx context.Context, orgID, appID, envID s fallthrough default: - return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode)) + return nil, resError(req, resp) } } diff --git a/internal/humanitec_go/client/deployments_test.go b/internal/humanitec_go/client/deployments_test.go index c4970eb..a8cd6ec 100644 --- a/internal/humanitec_go/client/deployments_test.go +++ b/internal/humanitec_go/client/deployments_test.go @@ -83,7 +83,8 @@ func TestStartDeployment(t *testing.T) { { Name: "Should handle API errors", StatusCode: []int{http.StatusInternalServerError}, - ExpectedError: errors.New("HTTP 500"), + Response: []byte(`error details`), + ExpectedError: errors.New("unexpected response status 500 - Internal Server Error\nerror details"), }, { Name: "Should handle response parsing errors", @@ -99,7 +100,8 @@ func TestStartDeployment(t *testing.T) { }, Retry: false, StatusCode: []int{http.StatusConflict}, - ExpectedError: errors.New("HTTP 409"), + Response: []byte(`conflict details`), + ExpectedError: errors.New("unexpected response status 409 - Conflict\nconflict details"), }, { Name: "Should retry conflict errors with retry", diff --git a/internal/humanitec_go/client/resources.go b/internal/humanitec_go/client/resources.go index 6a052e7..359a3c4 100644 --- a/internal/humanitec_go/client/resources.go +++ b/internal/humanitec_go/client/resources.go @@ -48,6 +48,6 @@ func (api *apiClient) ListResourceTypes(ctx context.Context, orgID string) ([]hu } default: - return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode)) + return nil, resError(req, resp) } } diff --git a/internal/humanitec_go/client/resources_test.go b/internal/humanitec_go/client/resources_test.go index aaf1e20..8c04b6b 100644 --- a/internal/humanitec_go/client/resources_test.go +++ b/internal/humanitec_go/client/resources_test.go @@ -88,7 +88,8 @@ func TestListResourceTypes(t *testing.T) { { Name: "Should handle API errors", StatusCode: http.StatusInternalServerError, - ExpectedError: errors.New("HTTP 500"), + ExpectedError: errors.New("unexpected response status 500 - Internal Server Error\nerror details"), + Response: []byte(`error details`), }, { Name: "Should handle response parsing errors",