package app import ( "strings" "forge.cadoles.com/arcad/edge/pkg/bundle" "github.com/pkg/errors" "golang.org/x/mod/semver" "gopkg.in/yaml.v2" ) type ID string type Manifest struct { ID ID `yaml:"id" json:"id"` Version string `yaml:"version" json:"version"` Title string `yaml:"title" json:"title"` Description string `yaml:"description" json:"description"` Tags []string `yaml:"tags" json:"tags"` Metadata map[string]any `yaml:"metadata" json:"metadata"` } type MetadataValidator func(map[string]any) (bool, error) func (m *Manifest) Validate(validators ...MetadataValidator) (bool, error) { if m.ID == "" { return false, errors.New("'id' property should not be empty") } if m.Version == "" { return false, errors.New("'version' property should not be empty") } version := m.Version if !strings.HasPrefix(version, "v") { version = "v" + version } if !semver.IsValid(version) { return false, errors.Errorf("version '%s' does not respect semver format", m.Version) } if m.Title == "" { return false, errors.New("'title' property should not be empty") } if m.Tags != nil { for _, t := range m.Tags { if strings.ContainsAny(t, " \t\n\r") { return false, errors.Errorf("tag '%s' should not contain any space or new line", t) } } } for _, v := range validators { valid, err := v(m.Metadata) if !valid || err != nil { return valid, errors.WithStack(err) } } return true, nil } func LoadManifest(b bundle.Bundle) (*Manifest, error) { reader, _, err := b.File("manifest.yml") if err != nil { return nil, errors.Wrap(err, "could not read manifest.yml") } defer func() { if err := reader.Close(); err != nil { panic(errors.WithStack(err)) } }() manifest := &Manifest{} decoder := yaml.NewDecoder(reader) if err := decoder.Decode(manifest); err != nil { return nil, errors.Wrap(err, "could not decode manifest.yml") } return manifest, nil }