cli: improve error reporting in metadata apply command

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4454
Co-authored-by: Aravind K P <8335904+scriptonist@users.noreply.github.com>
GitOrigin-RevId: ae66bdfdc140c1a2a7747fb0ff2acd6f7b577d3f
This commit is contained in:
Divi 2022-06-15 21:14:36 +05:30 committed by hasura-bot
parent 132dffe4cf
commit c668aa1158
18 changed files with 68 additions and 37 deletions

View File

@ -15,6 +15,7 @@ Event Triggers support has been added for MS SQL Server. Now, you can invoke ext
- console: add GraphQL field customization for new database connections (root fields namespace, prefix, and suffix, and type names prefix and suffix) - console: add GraphQL field customization for new database connections (root fields namespace, prefix, and suffix, and type names prefix and suffix)
- console: add support for mssql event triggers - console: add support for mssql event triggers
- cli: fix perfomance regression with large metadata in `metadata apply` - cli: fix perfomance regression with large metadata in `metadata apply`
- cli: fix error reporting in `metadata apply` command (#8280)
## v2.8.0 ## v2.8.0

View File

@ -461,7 +461,7 @@ func (a *ActionConfig) BaseDirectory() string {
} }
func (a *ActionConfig) GetActionsFileContent() (content types.Common, err error) { func (a *ActionConfig) GetActionsFileContent() (content types.Common, err error) {
commonByt, err := ioutil.ReadFile(filepath.Join(a.MetadataDir, a.Filename())) commonByt, err := metadataobject.ReadMetadataFile(filepath.Join(a.MetadataDir, a.Filename()))
if err != nil { if err != nil {
return return
} }
@ -470,7 +470,7 @@ func (a *ActionConfig) GetActionsFileContent() (content types.Common, err error)
} }
func (a *ActionConfig) GetActionsGraphQLFileContent() (sdl string, err error) { func (a *ActionConfig) GetActionsGraphQLFileContent() (sdl string, err error) {
commonByt, err := ioutil.ReadFile(filepath.Join(a.MetadataDir, graphqlFileName)) commonByt, err := metadataobject.ReadMetadataFile(filepath.Join(a.MetadataDir, graphqlFileName))
if err != nil { if err != nil {
return return
} }

View File

@ -43,7 +43,7 @@ func (a *AllowListConfig) CreateFiles() error {
} }
func (a *AllowListConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (a *AllowListConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(a.MetadataDir, a.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(a.MetadataDir, a.Filename()))
if err != nil { if err != nil {
return nil, a.error(err) return nil, a.error(err)
} }

View File

@ -51,7 +51,7 @@ type apiLimitsObject struct {
} }
func (o *MetadataObject) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (o *MetadataObject) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(o.MetadataDir, o.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(o.MetadataDir, o.Filename()))
if err != nil { if err != nil {
return nil, o.error(err) return nil, o.error(err)
} }

View File

@ -46,7 +46,7 @@ func (c *CronTriggers) CreateFiles() error {
} }
func (c *CronTriggers) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (c *CronTriggers) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(c.MetadataDir, c.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(c.MetadataDir, c.Filename()))
if err != nil { if err != nil {
return nil, c.error(err) return nil, c.error(err)
} }

View File

@ -42,7 +42,7 @@ func (f *FunctionConfig) CreateFiles() error {
} }
func (f *FunctionConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (f *FunctionConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(f.MetadataDir, f.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(f.MetadataDir, f.Filename()))
if err != nil { if err != nil {
return nil, f.error(err) return nil, f.error(err)
} }

View File

@ -48,7 +48,7 @@ type graphQLSchemaIntrospectionObject struct {
} }
func (o *MetadataObject) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (o *MetadataObject) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(o.MetadataDir, o.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(o.MetadataDir, o.Filename()))
if err != nil { if err != nil {
return nil, o.error(err) return nil, o.error(err)
} }

View File

@ -1,7 +1,6 @@
package inheritedroles package inheritedroles
import ( import (
"io/ioutil"
"path/filepath" "path/filepath"
"github.com/hasura/graphql-engine/cli/v2/internal/metadataobject" "github.com/hasura/graphql-engine/cli/v2/internal/metadataobject"
@ -36,7 +35,7 @@ func (ir *InheritedRolesConfig) CreateFiles() error {
} }
func (ir *InheritedRolesConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (ir *InheritedRolesConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(ir.MetadataDir, ir.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(ir.MetadataDir, ir.Filename()))
if err != nil { if err != nil {
return nil, ir.error(err) return nil, ir.error(err)
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -103,6 +104,16 @@ type Object interface {
BaseDirectory() string BaseDirectory() string
} }
var ErrMetadataFileNotFound = fmt.Errorf("metadata file not found")
func ReadMetadataFile(filename string) ([]byte, error) {
bytes, err := ioutil.ReadFile(filename)
if err != nil && errors.Is(err, fs.ErrNotExist) {
return nil, ErrMetadataFileNotFound
}
return bytes, err
}
type ErrParsingMetadataObject interface { type ErrParsingMetadataObject interface {
// ObjectName corresponds to metadata object in JSON format // ObjectName corresponds to metadata object in JSON format
// eg: source, api_limits etc // eg: source, api_limits etc

View File

@ -47,7 +47,7 @@ type networkObject struct {
} }
func (o *NetworkObject) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (o *NetworkObject) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(o.MetadataDir, o.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(o.MetadataDir, o.Filename()))
if err != nil { if err != nil {
return nil, o.error(err) return nil, o.error(err)
} }

View File

@ -49,7 +49,7 @@ func (q *QueryCollectionConfig) CreateFiles() error {
} }
func (q *QueryCollectionConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (q *QueryCollectionConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(q.MetadataDir, q.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(q.MetadataDir, q.Filename()))
if err != nil { if err != nil {
return nil, q.error(err) return nil, q.error(err)
} }

View File

@ -55,7 +55,7 @@ func (r *RemoteSchemaConfig) CreateFiles() error {
return nil return nil
} }
func (r *RemoteSchemaConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (r *RemoteSchemaConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(r.MetadataDir, r.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(r.MetadataDir, r.Filename()))
if err != nil { if err != nil {
return nil, r.error(err) return nil, r.error(err)
} }
@ -68,7 +68,7 @@ func (r *RemoteSchemaConfig) Build() (map[string]interface{}, metadataobject.Err
} }
type remoteSchema struct { type remoteSchema struct {
Name yaml.Node `yaml:"name,omitempty"` Name interface{} `yaml:"name,omitempty"`
Defintion yaml.Node `yaml:"definition,omitempty"` Defintion yaml.Node `yaml:"definition,omitempty"`
Comment yaml.Node `yaml:"comment,omitempty"` Comment yaml.Node `yaml:"comment,omitempty"`
Permissions []permission `yaml:"permissions,omitempty"` Permissions []permission `yaml:"permissions,omitempty"`
@ -76,7 +76,7 @@ type remoteSchema struct {
} }
type permission struct { type permission struct {
Role yaml.Node `yaml:"role,omitempty"` Role interface{} `yaml:"role,omitempty"`
Definition definition `yaml:"definition,omitempty"` Definition definition `yaml:"definition,omitempty"`
} }

View File

@ -45,7 +45,7 @@ func (re *RestEndpointsConfig) CreateFiles() error {
} }
func (re *RestEndpointsConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (re *RestEndpointsConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(re.MetadataDir, re.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(re.MetadataDir, re.Filename()))
if err != nil { if err != nil {
return nil, re.error(err) return nil, re.error(err)
} }

View File

@ -72,7 +72,7 @@ func (t *SourceConfig) CreateFiles() error {
func (t *SourceConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (t *SourceConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
sourceFile := filepath.Join(t.MetadataDir, sourcesDirectory, t.Filename()) sourceFile := filepath.Join(t.MetadataDir, sourcesDirectory, t.Filename())
sourcesBytes, err := ioutil.ReadFile(sourceFile) sourcesBytes, err := metadataobject.ReadMetadataFile(sourceFile)
if err != nil { if err != nil {
return nil, t.error(err) return nil, t.error(err)
} }

View File

@ -43,7 +43,7 @@ func (t *TableConfig) CreateFiles() error {
} }
func (t *TableConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (t *TableConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(t.MetadataDir, t.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(t.MetadataDir, t.Filename()))
if err != nil { if err != nil {
return nil, t.error(err) return nil, t.error(err)
} }

View File

@ -50,7 +50,7 @@ func (a *VersionConfig) CreateFiles() error {
} }
func (a *VersionConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) { func (a *VersionConfig) Build() (map[string]interface{}, metadataobject.ErrParsingMetadataObject) {
data, err := ioutil.ReadFile(filepath.Join(a.MetadataDir, a.Filename())) data, err := metadataobject.ReadMetadataFile(filepath.Join(a.MetadataDir, a.Filename()))
if err != nil { if err != nil {
return nil, a.error(err) return nil, a.error(err)
} }

View File

@ -61,18 +61,38 @@ func (f *fragment) UnmarshalYAML(value *yaml.Node) error {
return err return err
} }
var resolver = func(ctx map[string]string, node *yaml.Node, files *[]string) (*yaml.Node, error) { type YamlTagResolverError struct {
if node.Kind != yaml.ScalarNode { tag string
return nil, fmt.Errorf("found %s on scalar node", baseDirectoryKey) file string
err error
} }
func (e *YamlTagResolverError) Error() string {
if e.tag == "" {
return fmt.Sprintf("yaml tag resolver error: %s", e.err.Error())
}
return fmt.Sprintf(
"yaml tag resolver error:\ntag: %s\nfile: %s\nerror: %s",
e.tag,
e.file,
e.err.Error(),
)
}
func (e *YamlTagResolverError) Unwrap() error {
return e.err
}
var resolver = func(ctx map[string]string, node *yaml.Node, files *[]string) (*yaml.Node, error) {
baseDir, ok := ctx[baseDirectoryKey] baseDir, ok := ctx[baseDirectoryKey]
if !ok { if !ok {
return nil, fmt.Errorf("parser error: base directory for !include tag not specified") return nil, &YamlTagResolverError{"", "", fmt.Errorf("parser error: base directory for !include tag not specified")}
} }
fileLocation := filepath.Join(baseDir, node.Value) fileLocation := filepath.Join(baseDir, node.Value)
file, err := ioutil.ReadFile(fileLocation) file, err := ioutil.ReadFile(fileLocation)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %w", fileLocation, err) return nil, &YamlTagResolverError{node.Tag, fileLocation, err}
} }
if files != nil { if files != nil {
*files = append(*files, fileLocation) *files = append(*files, fileLocation)
@ -89,12 +109,23 @@ var resolver = func(ctx map[string]string, node *yaml.Node, files *[]string) (*y
var f = newFragment(newctx, files) var f = newFragment(newctx, files)
err = yaml.Unmarshal(file, f) err = yaml.Unmarshal(file, f)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %w", fileLocation, err) return nil, &YamlTagResolverError{node.Tag, fileLocation, err}
} }
return f.content, nil return f.content, nil
} }
func resolveTags(ctx map[string]string, node *yaml.Node, files *[]string) (*yaml.Node, error) { func resolveTags(ctx map[string]string, node *yaml.Node, files *[]string) (*yaml.Node, error) {
switch node.Kind {
case yaml.DocumentNode, yaml.SequenceNode, yaml.MappingNode:
var err error
for idx := range node.Content {
node.Content[idx], err = resolveTags(ctx, node.Content[idx], files)
if err != nil {
return nil, err
}
}
}
switch node.Tag { switch node.Tag {
case includeTag: case includeTag:
return resolver(ctx, node, files) return resolver(ctx, node, files)
@ -107,16 +138,6 @@ func resolveTags(ctx map[string]string, node *yaml.Node, files *[]string) (*yaml
} }
} }
switch node.Kind {
case yaml.DocumentNode, yaml.SequenceNode, yaml.MappingNode:
var err error
for idx := range node.Content {
node.Content[idx], err = resolveTags(ctx, node.Content[idx], files)
if err != nil {
return nil, err
}
}
}
return node, nil return node, nil
} }

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -115,7 +114,7 @@ func (h *Handler) buildMetadataMap() (map[string]interface{}, error) {
for _, object := range h.objects { for _, object := range h.objects {
objectMetadata, err := object.Build() objectMetadata, err := object.Build()
if err != nil { if err != nil {
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, metadataobject.ErrMetadataFileNotFound) {
h.logger.Debugf("metadata file for %s was not found, assuming an empty file", object.Key()) h.logger.Debugf("metadata file for %s was not found, assuming an empty file", object.Key())
continue continue
} }