github.com/argoproj/argo-events@v1.9.1/hack/gen-openapi-spec/main.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "log" 6 "os" 7 "strings" 8 9 "k8s.io/kube-openapi/pkg/common" 10 "k8s.io/kube-openapi/pkg/validation/spec" 11 12 cv1 "github.com/argoproj/argo-events/pkg/apis/common" 13 ebv1 "github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1" 14 esv1 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" 15 sv1 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" 16 ) 17 18 type ( 19 obj = map[string]interface{} 20 ) 21 22 // Generate OpenAPI spec definitions for Workflow Resource 23 func main() { 24 if len(os.Args) <= 3 { 25 log.Fatal("Supply a version") 26 } 27 log.Println(os.Args) 28 version := os.Args[1] 29 kubeSwaggerPath := os.Args[2] 30 output := os.Args[3] 31 if version != "latest" && !strings.HasPrefix(version, "v") { 32 version = "v" + version 33 } 34 referenceCallback := func(name string) spec.Ref { 35 return spec.MustCreateRef("#/definitions/" + common.EscapeJsonPointer(swaggify(name))) 36 } 37 defs := spec.Definitions{} 38 dependencies := []string{} 39 for defName, val := range cv1.GetOpenAPIDefinitions(referenceCallback) { 40 defs[swaggify(defName)] = val.Schema 41 dependencies = append(dependencies, val.Dependencies...) 42 } 43 for defName, val := range ebv1.GetOpenAPIDefinitions(referenceCallback) { 44 defs[swaggify(defName)] = val.Schema 45 dependencies = append(dependencies, val.Dependencies...) 46 } 47 for defName, val := range esv1.GetOpenAPIDefinitions(referenceCallback) { 48 defs[swaggify(defName)] = val.Schema 49 dependencies = append(dependencies, val.Dependencies...) 50 } 51 for defName, val := range sv1.GetOpenAPIDefinitions(referenceCallback) { 52 defs[swaggify(defName)] = val.Schema 53 dependencies = append(dependencies, val.Dependencies...) 54 } 55 56 k8sDefinitions := getKubernetesSwagger(kubeSwaggerPath) 57 for _, dep := range dependencies { 58 if !strings.Contains(dep, "k8s.io") { 59 continue 60 } 61 d := swaggify(dep) 62 if kd, ok := k8sDefinitions[d]; ok { 63 defs[d] = kd 64 } 65 } 66 for d, s := range k8sDefinitions { 67 defs[d] = s 68 } 69 70 swagger := &spec.Swagger{ 71 SwaggerProps: spec.SwaggerProps{ 72 Swagger: "2.0", 73 Definitions: defs, 74 Paths: &spec.Paths{Paths: map[string]spec.PathItem{}}, 75 Info: &spec.Info{ 76 InfoProps: spec.InfoProps{ 77 Title: "Argo Events", 78 Version: version, 79 }, 80 }, 81 }, 82 } 83 84 jsonBytes, err := json.MarshalIndent(swagger, "", " ") 85 if err != nil { 86 log.Fatal(err.Error()) 87 } 88 err = os.WriteFile(output, jsonBytes, 0644) 89 if err != nil { 90 panic(err) 91 } 92 f, err := os.Open(output) 93 if err != nil { 94 panic(err) 95 } 96 // filter out "default" fields from swagger definitions properties because they are being set to empty strings and it makes the swagger validation fail. 97 swaggerObj := obj{} 98 err = json.NewDecoder(f).Decode(&swaggerObj) 99 if err != nil { 100 panic(err) 101 } 102 definitions := swaggerObj["definitions"].(obj) 103 104 for _, d := range definitions { 105 props, ok := d.(obj)["properties"].(obj) 106 if ok { 107 for _, prop := range props { 108 prop := prop.(obj) 109 delete(prop, "default") 110 items, ok := prop["items"].(obj) 111 if ok { 112 delete(items, "default") 113 } 114 additionalProperties, ok := prop["additionalProperties"].(obj) 115 if ok { 116 delete(additionalProperties, "default") 117 } 118 } 119 } 120 props, ok = d.(obj)["additionalProperties"].(obj) 121 if ok { 122 delete(props, "default") 123 } 124 } 125 126 f, err = os.Create(output) 127 if err != nil { 128 panic(err) 129 } 130 e := json.NewEncoder(f) 131 e.SetIndent("", " ") 132 err = e.Encode(swaggerObj) 133 if err != nil { 134 panic(err) 135 } 136 err = f.Close() 137 if err != nil { 138 panic(err) 139 } 140 } 141 142 // swaggify converts the github package 143 // e.g.: 144 // github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1.Sensor 145 // to: 146 // io.argoproj.v1alpha1.Sensor 147 func swaggify(name string) string { 148 name = strings.ReplaceAll(name, "github.com/argoproj/argo-events/pkg/apis", "argoproj.io") 149 parts := strings.Split(name, "/") 150 hostParts := strings.Split(parts[0], ".") 151 // reverses something like k8s.io to io.k8s 152 for i, j := 0, len(hostParts)-1; i < j; i, j = i+1, j-1 { 153 hostParts[i], hostParts[j] = hostParts[j], hostParts[i] 154 } 155 parts[0] = strings.Join(hostParts, ".") 156 return strings.Join(parts, ".") 157 } 158 159 func getKubernetesSwagger(kubeSwaggerPath string) spec.Definitions { 160 data, err := os.ReadFile(kubeSwaggerPath) 161 if err != nil { 162 panic(err) 163 } 164 swagger := &spec.Swagger{} 165 err = json.Unmarshal(data, swagger) 166 if err != nil { 167 panic(err) 168 } 169 return swagger.Definitions 170 }