cli: improve error messages for metadata apply (close #5513) (#5548)

This commit is contained in:
Aravind 2020-08-10 10:54:00 +05:30 committed by GitHub
parent 788d8678a7
commit 2592236858
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 19 deletions

View File

@ -24,6 +24,7 @@ If you do have such headers configured, then you must update the header configur
- console: handle nested fragments in allowed queries (close #5137) (#5252)
- console: update sidebar icons for different action and trigger types (#5445)
- console: make add column UX consistent with others (#5486)
- cli: improve error messages thrown when metadata apply fails (#5513)
- build: introduce additional log kinds for cli-migrations image (#5529)
## `v1.3.0`

View File

@ -219,7 +219,7 @@ func (h *HasuraDB) ApplyMetadata() error {
if err != nil {
return err
}
herror.migrationQuery = "offending object: \n\r\n\r" + string(queryData)
h.logger.Debugf("offending object: \n\r\n\r" + string(queryData))
}
}
return herror

View File

@ -289,11 +289,35 @@ type HasuraError struct {
Code string `json:"code"`
}
type InconsistentMetadataError struct {
Definition interface{} `json:"definition,omitempty" mapstructure:"definition,omitempty"`
Reason string `json:"reason,omitempty" mapstructure:"reason,omitempty"`
Type string `json:"type,omitempty" mapstructure:"type,omitempty"`
}
func (mderror *InconsistentMetadataError) String() string {
var out string
if mderror.Reason != "" {
out = fmt.Sprintf("\nreason: %v\n", mderror.Reason)
}
if mderror.Type != "" {
out = fmt.Sprintf("%stype: %v\n", out, mderror.Type)
}
if mderror.Definition != nil {
m, err := json.MarshalIndent(mderror.Definition, "", " ")
if err == nil {
out = fmt.Sprintf("%sdefinition: \n%s", out, string(m))
}
}
return out
}
type SQLInternalError struct {
Arguments []string `json:"arguments" mapstructure:"arguments,omitempty"`
Error PostgresError `json:"error" mapstructure:"error,omitempty"`
Prepared bool `json:"prepared" mapstructure:"prepared,omitempty"`
Statement string `json:"statement" mapstructure:"statement,omitempty"`
Arguments []string `json:"arguments" mapstructure:"arguments,omitempty"`
Error *PostgresError `json:"error" mapstructure:"error,omitempty"`
Prepared bool `json:"prepared" mapstructure:"prepared,omitempty"`
Statement string `json:"statement" mapstructure:"statement,omitempty"`
InconsistentMetadataError `mapstructure:",squash"`
}
type PostgresError struct {
StatusCode string `json:"status_code" mapstructure:"status_code,omitempty"`
@ -323,20 +347,7 @@ func (h HasuraError) Error() string {
err := mapstructure.Decode(v, &internalError)
if err == nil {
// postgres error
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", internalError.Error.StatusCode, internalError.Error.ExecStatus, internalError.Error.Message))
if len(internalError.Error.Description) > 0 {
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", internalError.Error.Description))
}
if len(internalError.Error.Hint) > 0 {
errorStrings = append(errorStrings, fmt.Sprintf("Hint: %s", internalError.Error.Hint))
}
}
}
if v, ok := h.Internal.([]interface{}); ok {
err := mapstructure.Decode(v, &internalErrors)
if err == nil {
for _, internalError := range internalErrors {
// postgres error
if internalError.Error != nil {
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", internalError.Error.StatusCode, internalError.Error.ExecStatus, internalError.Error.Message))
if len(internalError.Error.Description) > 0 {
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", internalError.Error.Description))
@ -345,8 +356,35 @@ func (h HasuraError) Error() string {
errorStrings = append(errorStrings, fmt.Sprintf("Hint: %s", internalError.Error.Hint))
}
}
if e := internalError.InconsistentMetadataError.String(); e != "" {
errorStrings = append(errorStrings, e)
}
}
}
if v, ok := h.Internal.([]interface{}); ok {
err := mapstructure.Decode(v, &internalErrors)
if err == nil {
for _, internalError := range internalErrors {
// postgres error
if internalError.Error != nil {
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", internalError.Error.StatusCode, internalError.Error.ExecStatus, internalError.Error.Message))
if len(internalError.Error.Description) > 0 {
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", internalError.Error.Description))
}
if len(internalError.Error.Hint) > 0 {
errorStrings = append(errorStrings, fmt.Sprintf("Hint: %s", internalError.Error.Hint))
}
}
if e := internalError.InconsistentMetadataError.String(); e != "" {
errorStrings = append(errorStrings, e)
}
}
}
}
if len(errorStrings) == 0 {
return ""
}
return strings.Join(errorStrings, "\r\n")
}

View File

@ -72,3 +72,94 @@ func TestHasuraError_Error(t *testing.T) {
})
}
}
func TestInconsistentMetadataError_String(t *testing.T) {
type fields struct {
Definition interface{}
Reason string
Type string
}
tests := []struct {
name string
fields fields
want string
}{
{
"can generate error correctly when all fields are given",
fields{
Reason: "test reason",
Type: "test",
Definition: func() interface{} {
var m interface{}
err := json.Unmarshal([]byte(`{"test": "test"}`), &m)
if err != nil {
t.Error(err)
}
return m
}(),
},
`
reason: test reason
type: test
definition:
{
"test": "test"
}`,
},
{
"will not panic when Definition is not a valid json (string)",
fields{
Definition: func() interface{} {
return "test"
}(),
Reason: "",
Type: "",
},
`definition:
"test"`,
},
{
"will not panic when Definition is not a valid json (Int)",
fields{
Definition: func() interface{} {
return 1
}(),
Reason: "",
Type: "",
},
`definition:
1`,
},
{
"will not panic when Definition is (struct Array)",
fields{
Definition: func() interface{} {
return []struct{Name string}{ { "test" } , { "test"} }
}(),
Reason: "",
Type: "",
},
`definition:
[
{
"Name": "test"
},
{
"Name": "test"
}
]`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mderror := &InconsistentMetadataError{
Definition: tt.fields.Definition,
Reason: tt.fields.Reason,
Type: tt.fields.Type,
}
if got := mderror.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}