summaryrefslogtreecommitdiffstats
path: root/modules/migration/file_format.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/migration/file_format.go110
1 files changed, 110 insertions, 0 deletions
diff --git a/modules/migration/file_format.go b/modules/migration/file_format.go
new file mode 100644
index 0000000..d29d24d
--- /dev/null
+++ b/modules/migration/file_format.go
@@ -0,0 +1,110 @@
+// 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/v6"
+ "gopkg.in/yaml.v3"
+)
+
+// Load project data from file, with optional validation
+func Load(filename string, data any, 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 any, 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.UseLoader(&SchemaLoader{})
+ return c.Compile(filename)
+}
+
+func validate(bs []byte, datatype any, isJSON bool) error {
+ var v any
+ 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 any) (any, error) {
+ var err error
+ switch val := val.(type) {
+ case map[string]any:
+ m := make(map[string]any)
+ for k, v := range val {
+ m[k], err = toStringKeys(v)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return m, nil
+ case []any:
+ l := make([]any, 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
+ }
+}