123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- // Copyright 2022 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package migration
-
- import (
- "fmt"
- "os"
- "strings"
- "time"
-
- "code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/log"
-
- "github.com/santhosh-tekuri/jsonschema/v5"
- "gopkg.in/yaml.v3"
- )
-
- // Load project data from file, with optional validation
- func Load(filename string, data interface{}, validation bool) error {
- isJSON := strings.HasSuffix(filename, ".json")
-
- bs, err := os.ReadFile(filename)
- if err != nil {
- return err
- }
-
- if validation {
- err := validate(bs, data, isJSON)
- if err != nil {
- return err
- }
- }
- return unmarshal(bs, data, isJSON)
- }
-
- func unmarshal(bs []byte, data interface{}, isJSON bool) error {
- if isJSON {
- return json.Unmarshal(bs, data)
- }
- return yaml.Unmarshal(bs, data)
- }
-
- func getSchema(filename string) (*jsonschema.Schema, error) {
- c := jsonschema.NewCompiler()
- c.LoadURL = openSchema
- return c.Compile(filename)
- }
-
- func validate(bs []byte, datatype interface{}, isJSON bool) error {
- var v interface{}
- err := unmarshal(bs, &v, isJSON)
- if err != nil {
- return err
- }
- if !isJSON {
- v, err = toStringKeys(v)
- if err != nil {
- return err
- }
- }
-
- var schemaFilename string
- switch datatype := datatype.(type) {
- case *[]*Issue:
- schemaFilename = "issue.json"
- case *[]*Milestone:
- schemaFilename = "milestone.json"
- default:
- return fmt.Errorf("file_format:validate: %T has not a validation implemented", datatype)
- }
-
- sch, err := getSchema(schemaFilename)
- if err != nil {
- return err
- }
- err = sch.Validate(v)
- if err != nil {
- log.Error("migration validation with %s failed:\n%#v", schemaFilename, err)
- }
- return err
- }
-
- func toStringKeys(val interface{}) (interface{}, error) {
- var err error
- switch val := val.(type) {
- case map[string]interface{}:
- m := make(map[string]interface{})
- for k, v := range val {
- m[k], err = toStringKeys(v)
- if err != nil {
- return nil, err
- }
- }
- return m, nil
- case []interface{}:
- l := make([]interface{}, len(val))
- for i, v := range val {
- l[i], err = toStringKeys(v)
- if err != nil {
- return nil, err
- }
- }
- return l, nil
- case time.Time:
- return val.Format(time.RFC3339), nil
- default:
- return val, nil
- }
- }
|