This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push: new 31c66e7b4 fix(ci): bring back CLIs required by ci tasks 31c66e7b4 is described below commit 31c66e7b4d30efdee76335f843575513cd31b263 Author: Pasquale Congiusti <pasquale.congiu...@gmail.com> AuthorDate: Tue Jun 6 15:31:57 2023 +0200 fix(ci): bring back CLIs required by ci tasks Closes #4460 --- cmd/util/doc-gen/generators/generators.go | 69 +++++ cmd/util/doc-gen/generators/traitdocgen.go | 328 ++++++++++++++++++++++++ cmd/util/doc-gen/generators/traitmetadatagen.go | 183 +++++++++++++ cmd/util/doc-gen/main.go | 47 ++++ cmd/util/json-schema-gen/main.go | 174 +++++++++++++ cmd/util/license-check/main.go | 55 ++++ cmd/util/platform-check/main.go | 68 +++++ go.mod | 3 + go.sum | 4 + 9 files changed, 931 insertions(+) diff --git a/cmd/util/doc-gen/generators/generators.go b/cmd/util/doc-gen/generators/generators.go new file mode 100644 index 000000000..09d66c501 --- /dev/null +++ b/cmd/util/doc-gen/generators/generators.go @@ -0,0 +1,69 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "path/filepath" + "strings" + + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" +) + +// CustomArgs --. +type CustomArgs struct { + DocDir string + ResourceDir string + TraitPath string + NavPath string + ListPath string +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "default": namer.NewPublicNamer(0), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "default" +} + +// Packages --. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + var packages generator.Packages + for _, i := range context.Inputs { + pkg := context.Universe[i] + if pkg == nil { + continue + } + + packages = append(packages, &generator.DefaultPackage{ + PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0], + PackagePath: pkg.Path, + GeneratorFunc: func(c *generator.Context) []generator.Generator { + return []generator.Generator{NewTraitDocGen(arguments), NewtraitMetaDataGen(arguments)} + }, + }) + } + return packages +} diff --git a/cmd/util/doc-gen/generators/traitdocgen.go b/cmd/util/doc-gen/generators/traitdocgen.go new file mode 100644 index 000000000..08f8c69af --- /dev/null +++ b/cmd/util/doc-gen/generators/traitdocgen.go @@ -0,0 +1,328 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "io" + "os" + "path" + "reflect" + "regexp" + "sort" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/types" + + v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" + "github.com/apache/camel-k/v2/pkg/trait" + "github.com/apache/camel-k/v2/pkg/util" +) + +const ( + tagTrait = "+camel-k:trait" + tagLint = "nolint" + + adocCommonMarkerStart = "// Start of autogenerated code - DO NOT EDIT!" + adocCommonMarkerEnd = "// End of autogenerated code - DO NOT EDIT!" + + adocDescriptionMarkerStart = adocCommonMarkerStart + " (description)" + adocDescriptionMarkerEnd = adocCommonMarkerEnd + " (description)" + + adocConfigurationMarkerStart = adocCommonMarkerStart + " (configuration)" + adocConfigurationMarkerEnd = adocCommonMarkerEnd + " (configuration)" + + adocNavMarkerStart = adocCommonMarkerStart + " (trait-nav)" + adocNavMarkerEnd = adocCommonMarkerEnd + " (trait-nav)" +) + +var tagTraitID = regexp.MustCompile(fmt.Sprintf("%s=([a-z0-9-]+)", regexp.QuoteMeta(tagTrait))) + +// traitDocGen produces documentation about traits. +type traitDocGen struct { + generator.DefaultGen + arguments *args.GeneratorArgs + generatedTraitFiles []string +} + +// traitDocGen implements Generator interface. +var _ generator.Generator = &traitDocGen{} + +func NewTraitDocGen(arguments *args.GeneratorArgs) generator.Generator { + return &traitDocGen{ + DefaultGen: generator.DefaultGen{}, + arguments: arguments, + } +} + +func (g *traitDocGen) Filename() string { + return "zz_generated_doc.go" +} + +func (g *traitDocGen) Filter(context *generator.Context, t *types.Type) bool { + for _, c := range t.CommentLines { + if strings.Contains(c, tagTrait) { + return true + } + } + return false +} + +func (g *traitDocGen) GenerateType(context *generator.Context, t *types.Type, out io.Writer) error { + customArgs, ok := g.arguments.CustomArgs.(*CustomArgs) + if !ok { + return fmt.Errorf("type assertion failed: %v", g.arguments.CustomArgs) + } + docDir := customArgs.DocDir + traitPath := customArgs.TraitPath + traitID := getTraitID(t) + traitFile := traitID + ".adoc" + filename := path.Join(docDir, traitPath, traitFile) + + g.generatedTraitFiles = append(g.generatedTraitFiles, traitFile) + + return util.WithFileContent(filename, func(file *os.File, data []byte) error { + content := strings.Split(string(data), "\n") + + writeTitle(traitID, &content) + writeDescription(t, traitID, &content) + writeFields(t, traitID, &content) + + return writeFile(file, content) + }) +} + +func (g *traitDocGen) Finalize(c *generator.Context, w io.Writer) error { + return g.FinalizeNav(c) +} + +func (g *traitDocGen) FinalizeNav(*generator.Context) error { + customArgs, ok := g.arguments.CustomArgs.(*CustomArgs) + if !ok { + return fmt.Errorf("type assertion failed: %v", g.arguments.CustomArgs) + } + docDir := customArgs.DocDir + navPath := customArgs.NavPath + filename := path.Join(docDir, navPath) + + return util.WithFileContent(filename, func(file *os.File, data []byte) error { + content := strings.Split(string(data), "\n") + + pre, post := split(content, adocNavMarkerStart, adocNavMarkerEnd) + + content = append([]string(nil), pre...) + content = append(content, adocNavMarkerStart) + sort.Strings(g.generatedTraitFiles) + for _, t := range g.generatedTraitFiles { + name := traitNameFromFile(t) + content = append(content, "** xref:traits:"+t+"["+name+"]") + } + content = append(content, adocNavMarkerEnd) + content = append(content, post...) + + return writeFile(file, content) + }) +} + +func traitNameFromFile(file string) string { + name := strings.TrimSuffix(file, ".adoc") + name = strings.ReplaceAll(name, "trait", "") + name = strings.ReplaceAll(name, "-", " ") + name = strings.Trim(name, " ") + name = cases.Title(language.English).String(name) + return name +} + +func writeTitle(traitID string, content *[]string) { + res := append([]string(nil), *content...) + for _, s := range res { + if strings.HasPrefix(s, "= ") { + // Already has a title + return + } + } + res = append([]string{"= " + cases.Title(language.English).String(strings.ReplaceAll(traitID, "-", " ")) + " Trait"}, res...) + *content = res +} + +func writeDescription(t *types.Type, traitID string, content *[]string) { + pre, post := split(*content, adocDescriptionMarkerStart, adocDescriptionMarkerEnd) + res := append([]string(nil), pre...) + res = append(res, adocDescriptionMarkerStart) + res = append(res, filterOutTagsAndComments(t.CommentLines)...) + profiles := strings.Join(determineProfiles(traitID), ", ") + res = append(res, "", fmt.Sprintf("This trait is available in the following profiles: **%s**.", profiles)) + if isPlatformTrait(traitID) { + res = append(res, "", fmt.Sprintf("WARNING: The %s trait is a *platform trait*: disabling it may compromise the platform functionality.", traitID)) + } + res = append(res, "", adocDescriptionMarkerEnd) + res = append(res, post...) + *content = res +} + +func writeFields(t *types.Type, traitID string, content *[]string) { + pre, post := split(*content, adocConfigurationMarkerStart, adocConfigurationMarkerEnd) + res := append([]string(nil), pre...) + res = append(res, adocConfigurationMarkerStart, "== Configuration", "") + res = append(res, "Trait properties can be specified when running any integration with the CLI:") + res = append(res, "[source,console]") + res = append(res, "----") + if len(t.Members) > 1 { + res = append(res, fmt.Sprintf("$ kamel run --trait %s.[key]=[value] --trait %s.[key2]=[value2] integration.groovy", traitID, traitID)) + } else { + res = append(res, fmt.Sprintf("$ kamel run --trait %s.[key]=[value] integration.groovy", traitID)) + } + res = append(res, "----") + res = append(res, "The following configuration options are available:", "") + res = append(res, "[cols=\"2m,1m,5a\"]", "|===") + res = append(res, "|Property | Type | Description", "") + writeMembers(t, traitID, &res) + res = append(res, "|===", "", adocConfigurationMarkerEnd) + res = append(res, post...) + *content = res +} + +func writeMembers(t *types.Type, traitID string, content *[]string) { + res := append([]string(nil), *content...) + for _, m := range t.Members { + prop := reflect.StructTag(m.Tags).Get("property") + if prop == "" { + continue + } + + if strings.Contains(prop, "squash") { + writeMembers(m.Type, traitID, &res) + } else { + res = append(res, "| "+traitID+"."+prop) + res = append(res, "| "+strings.TrimPrefix(m.Type.Name.Name, "*")) + first := true + for _, l := range filterOutTagsAndComments(m.CommentLines) { + escapedComment := escapeASCIIDoc(l) + if first { + res = append(res, "| "+escapedComment) + first = false + } else { + res = append(res, escapedComment) + } + } + res = append(res, "") + } + } + *content = res +} + +func getTraitID(t *types.Type) string { + for _, s := range t.CommentLines { + if strings.Contains(s, tagTrait) { + matches := tagTraitID.FindStringSubmatch(s) + if len(matches) < 2 { + panic(fmt.Sprintf("unable to extract trait ID from tag line `%s`", s)) + } + return matches[1] + } + } + panic(fmt.Sprintf("trait ID not found in type %s", t.Name.Name)) +} + +func filterOutTagsAndComments(comments []string) []string { + res := make([]string, 0, len(comments)) + for _, l := range comments { + if !strings.HasPrefix(strings.TrimLeft(l, " \t"), "+") && + !strings.HasPrefix(strings.TrimLeft(l, " \t"), "TODO:") && + !strings.HasPrefix(strings.TrimLeft(l, " \t"), tagLint) { + res = append(res, l) + } + } + return res +} + +// escapeAsciiDoc is in charge to escape those chars used for formatting purposes. +func escapeASCIIDoc(text string) string { + return strings.ReplaceAll(text, "|", "\\|") +} + +func split(doc []string, startMarker, endMarker string) ([]string, []string) { + if len(doc) == 0 { + return nil, nil + } + idx := len(doc) + for i, s := range doc { + if s == startMarker { + idx = i + break + } + } + idy := len(doc) + for j, s := range doc { + if j > idx && s == endMarker { + idy = j + break + } + } + pre := doc[0:idx] + post := []string{} + if idy < len(doc) { + post = doc[idy+1:] + } + return pre, post +} + +func writeFile(file *os.File, content []string) error { + if err := file.Truncate(0); err != nil { + return err + } + max := 0 + for i, line := range content { + if line != "" { + max = i + } + } + for i, line := range content { + if i <= max { + if _, err := file.WriteString(line + "\n"); err != nil { + return err + } + } + } + return nil +} + +func isPlatformTrait(traitID string) bool { + catalog := trait.NewCatalog(nil) + t := catalog.GetTrait(traitID) + return t.IsPlatformTrait() +} + +func determineProfiles(traitID string) []string { + var profiles []string + catalog := trait.NewCatalog(nil) + for _, p := range v1.AllTraitProfiles { + traits := catalog.TraitsForProfile(p) + for _, t := range traits { + if string(t.ID()) == traitID { + profiles = append(profiles, string(p)) + } + } + } + return profiles +} diff --git a/cmd/util/doc-gen/generators/traitmetadatagen.go b/cmd/util/doc-gen/generators/traitmetadatagen.go new file mode 100644 index 000000000..5d3f3e0ab --- /dev/null +++ b/cmd/util/doc-gen/generators/traitmetadatagen.go @@ -0,0 +1,183 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "io" + "os" + "path" + "reflect" + "sort" + "strings" + + "github.com/apache/camel-k/v2/pkg/util" + + "gopkg.in/yaml.v2" + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/types" +) + +const traitFile = "traits.yaml" + +// traitMetaDataGen produces YAML documentation about trait descriptions. +type traitMetaDataGen struct { + generator.DefaultGen + arguments *args.GeneratorArgs + Root *traitMetaDataRoot +} + +type traitMetaDataRoot struct { + Traits []traitMetaData `yaml:"traits"` +} + +type traitMetaData struct { + Name string `yaml:"name"` + Platform bool `yaml:"platform"` + Profiles []string `yaml:"profiles"` + Description string `yaml:"description"` + Properties []traitPropertyMetaData `yaml:"properties"` +} + +type traitPropertyMetaData struct { + Name string `yaml:"name"` + TypeName string `yaml:"type"` + Description string `yaml:"description"` +} + +// traitMetaDataGen implements Generator interface. +var _ generator.Generator = &traitMetaDataGen{} + +// NewtraitMetaDataGen --. +func NewtraitMetaDataGen(arguments *args.GeneratorArgs) generator.Generator { + return &traitMetaDataGen{ + DefaultGen: generator.DefaultGen{}, + arguments: arguments, + Root: &traitMetaDataRoot{}, + } +} + +func (g *traitMetaDataGen) Filename() string { + return "zz_desc_generated.go" +} + +func (g *traitMetaDataGen) Filter(context *generator.Context, t *types.Type) bool { + for _, c := range t.CommentLines { + if strings.Contains(c, tagTrait) { + return true + } + } + return false +} + +func (g *traitMetaDataGen) GenerateType(context *generator.Context, t *types.Type, out io.Writer) error { + traitID := g.getTraitID(t) + td := &traitMetaData{} + g.buildDescription(t, traitID, td) + g.buildFields(t, td) + g.Root.Traits = append(g.Root.Traits, *td) + return nil +} + +func (g *traitMetaDataGen) Finalize(c *generator.Context, w io.Writer) error { + customArgs, ok := g.arguments.CustomArgs.(*CustomArgs) + if !ok { + return fmt.Errorf("type assertion failed: %v", g.arguments.CustomArgs) + } + deployDir := customArgs.ResourceDir + filename := path.Join(deployDir, traitFile) + + // reorder the traits metadata so that it always gets the identical result + sort.Slice(g.Root.Traits, func(i, j int) bool { + return g.Root.Traits[i].Name < g.Root.Traits[j].Name + }) + + return util.WithFile(filename, os.O_RDWR|os.O_CREATE, 0o777, func(file *os.File) error { + if err := file.Truncate(0); err != nil { + return err + } + + data, err := yaml.Marshal(g.Root) + if err != nil { + fmt.Fprintf(file, "error: %v", err) + } + fmt.Fprintf(file, "%s", string(data)) + + return nil + }) +} + +func (g *traitMetaDataGen) getTraitID(t *types.Type) string { + for _, s := range t.CommentLines { + if strings.Contains(s, tagTrait) { + matches := tagTraitID.FindStringSubmatch(s) + if len(matches) < 2 { + panic(fmt.Sprintf("unable to extract trait ID from tag line `%s`", s)) + } + return matches[1] + } + } + panic(fmt.Sprintf("trait ID not found in type %s", t.Name.Name)) +} + +func (g *traitMetaDataGen) buildDescription(t *types.Type, traitID string, td *traitMetaData) { + desc := []string(nil) + desc = append(desc, filterOutTagsAndComments(t.CommentLines)...) + td.Name = traitID + td.Description = "" + for _, line := range desc { + text := strings.Trim(line, " ") + if len(text) == 0 { + continue + } + if len(td.Description) > 0 { + td.Description += " " + } + td.Description += text + } + td.Profiles = determineProfiles(traitID) + td.Platform = isPlatformTrait(traitID) +} + +func (g *traitMetaDataGen) buildFields(t *types.Type, td *traitMetaData) { + if len(t.Members) > 1 { + res := []string(nil) + g.buildMembers(t, &res, td) + } +} + +func (g *traitMetaDataGen) buildMembers(t *types.Type, content *[]string, td *traitMetaData) { + for _, m := range t.Members { + res := append([]string(nil), *content...) + prop := reflect.StructTag(m.Tags).Get("property") + if prop != "" { + if strings.Contains(prop, "squash") { + g.buildMembers(m.Type, &res, td) + } else { + pd := traitPropertyMetaData{} + pd.Name = prop + pd.TypeName = strings.TrimPrefix(m.Type.Name.Name, "*") + + res = append(res, filterOutTagsAndComments(m.CommentLines)...) + pd.Description = strings.Join(res, " ") + td.Properties = append(td.Properties, pd) + } + } + } +} diff --git a/cmd/util/doc-gen/main.go b/cmd/util/doc-gen/main.go new file mode 100644 index 000000000..b80d8bc54 --- /dev/null +++ b/cmd/util/doc-gen/main.go @@ -0,0 +1,47 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "github.com/apache/camel-k/v2/cmd/util/doc-gen/generators" + "github.com/spf13/pflag" + "k8s.io/gengo/args" + + _ "github.com/apache/camel-k/v2/addons" +) + +func main() { + arguments := args.Default() + + // Custom args. + customArgs := &generators.CustomArgs{} + pflag.CommandLine.StringVar(&customArgs.DocDir, "doc-dir", "./docs", "Root of the document directory.") + pflag.CommandLine.StringVar(&customArgs.ResourceDir, "resource-dir", "./resources", "Root of the resource directory.") + pflag.CommandLine.StringVar(&customArgs.TraitPath, "traits-path", "modules/traits/pages", "Path to the traits directory.") + pflag.CommandLine.StringVar(&customArgs.NavPath, "nav-path", "modules/ROOT/nav.adoc", "Path to the navigation file.") + pflag.CommandLine.StringVar(&customArgs.ListPath, "list-path", "modules/traits/pages/traits.adoc", "Path to the trait list file.") + arguments.CustomArgs = customArgs + + if err := arguments.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + panic(err) + } +} diff --git a/cmd/util/json-schema-gen/main.go b/cmd/util/json-schema-gen/main.go new file mode 100644 index 000000000..d5ebe78cd --- /dev/null +++ b/cmd/util/json-schema-gen/main.go @@ -0,0 +1,174 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "encoding/json" + "fmt" + "os" + "reflect" + "strings" + + "github.com/apache/camel-k/v2/pkg/util" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + clientscheme "k8s.io/client-go/kubernetes/scheme" + + "github.com/apache/camel-k/v2/pkg/util/kubernetes" +) + +func main() { + if len(os.Args) != 6 { + fmt.Fprintln(os.Stderr, `Use "json-schema-gen <crd> <schema> <path> <isArray> <destination>`) + os.Exit(1) + } + crd := os.Args[1] + schema := os.Args[2] + path := os.Args[3] + isArray := os.Args[4] == "true" + destination := os.Args[5] + + if err := generate(crd, schema, path, isArray, destination); err != nil { + panic(err) + } +} + +func generate(crdFilename, dslFilename, path string, isArray bool, destination string) error { + dslSchema, err := loadDslSchema(dslFilename) + if err != nil { + return err + } + if !isArray && dslSchema["type"] == "array" { + // nolint: forcetypeassert + dslSchema = dslSchema["items"].(map[string]interface{}) + } + + rebaseRefs(dslSchema) + + bytes, err := json.Marshal(dslSchema) + if err != nil { + return err + } + schema := apiextensionsv1.JSONSchemaProps{} + err = json.Unmarshal(bytes, &schema) + if err != nil { + return err + } + + crdSchema, err := loadCrdSchema(crdFilename) + if err != nil { + return err + } + // relocate definitions + if len(crdSchema.Definitions) > 0 { + panic("unexpected definitions found in CRD") + } + if isArray { + crdSchema.Definitions = schema.Items.Schema.Definitions + schema.Items.Schema.Definitions = apiextensionsv1.JSONSchemaDefinitions{} + } else { + crdSchema.Definitions = schema.Definitions + schema.Definitions = apiextensionsv1.JSONSchemaDefinitions{} + } + + // merge DSL schema into the CRD schema + ref := *crdSchema + paths := pathComponents(path) + for _, p := range paths[:len(paths)-1] { + ref = ref.Properties[p] + } + ref.Properties[paths[len(paths)-1]] = schema + + result, err := json.MarshalIndent(crdSchema, "", " ") + if err != nil { + return err + } + return os.WriteFile(destination, result, 0o600) +} + +func remapRef(ref string) string { + return "#" + strings.TrimPrefix(ref, "#/items") +} + +func rebaseRefs(schema map[string]interface{}) { + for k, v := range schema { + switch { + case k == "$ref" && reflect.TypeOf(v).Kind() == reflect.String: + schema[k] = remapRef(fmt.Sprintf("%v", v)) + case reflect.TypeOf(v).Kind() == reflect.Map: + if m, ok := v.(map[string]interface{}); ok { + rebaseRefs(m) + } + case reflect.TypeOf(v).Kind() == reflect.Slice: + if vs, ok := v.([]interface{}); ok { + for _, vv := range vs { + if reflect.TypeOf(vv).Kind() == reflect.Map { + if m, ok := vv.(map[string]interface{}); ok { + rebaseRefs(m) + } + } + } + } + } + } +} + +func loadDslSchema(filename string) (map[string]interface{}, error) { + bytes, err := util.ReadFile(filename) + if err != nil { + return nil, err + } + var dslSchema map[string]interface{} + if err := json.Unmarshal(bytes, &dslSchema); err != nil { + return nil, err + } + return dslSchema, nil +} + +func loadCrdSchema(filename string) (*apiextensionsv1.JSONSchemaProps, error) { + bytes, err := util.ReadFile(filename) + if err != nil { + return nil, err + } + scheme := clientscheme.Scheme + err = apiextensionsv1.AddToScheme(scheme) + if err != nil { + return nil, err + } + obj, err := kubernetes.LoadResourceFromYaml(scheme, string(bytes)) + if err != nil { + return nil, err + } + crd, ok := obj.(*apiextensionsv1.CustomResourceDefinition) + if !ok { + return nil, fmt.Errorf("type assertion failed: %v", obj) + } + + return crd.Spec.Versions[0].Schema.OpenAPIV3Schema, nil +} + +func pathComponents(path string) []string { + res := make([]string, 0) + for _, p := range strings.Split(path, ".") { + if len(strings.TrimSpace(p)) == 0 { + continue + } + res = append(res, p) + } + return res +} diff --git a/cmd/util/license-check/main.go b/cmd/util/license-check/main.go new file mode 100644 index 000000000..6d79257a6 --- /dev/null +++ b/cmd/util/license-check/main.go @@ -0,0 +1,55 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/apache/camel-k/v2/pkg/util" +) + +func main() { + if len(os.Args) != 3 { + fmt.Fprintln(os.Stderr, `Use "license-check <file> <license>`) + os.Exit(1) + } + + fileName := os.Args[1] + licenseName := os.Args[2] + + fileBin, err := util.ReadFile(fileName) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "cannot read file %s: %v\n", fileName, err) + os.Exit(1) + } + file := string(fileBin) + + licenseBin, err := util.ReadFile(licenseName) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "cannot read file %s: %v\n", licenseName, err) + os.Exit(1) + } + license := string(licenseBin) + + if !strings.Contains(file, license) { + _, _ = fmt.Fprintf(os.Stderr, "file %s does not contain license\n", fileName) + os.Exit(1) + } +} diff --git a/cmd/util/platform-check/main.go b/cmd/util/platform-check/main.go new file mode 100644 index 000000000..4b052b279 --- /dev/null +++ b/cmd/util/platform-check/main.go @@ -0,0 +1,68 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "os" + "strings" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +func main() { + fmt.Println(platformID()) +} + +func platformID() string { + client := APIClient() + _, apiResourceLists, err := client.Discovery().ServerGroupsAndResources() + exitOnError(err) + + for _, apiResList := range apiResourceLists { + // Should be version independent just in case image api is ever upgraded + if strings.Contains(apiResList.GroupVersion, "image.openshift.io") { + return "openshift" + } + } + + return "kubernetes" +} + +func exitOnError(err error) { + if err != nil { + fmt.Println("ERROR:", err) + os.Exit(1) + } +} + +func RestConfig() *rest.Config { + restConfig, err := config.GetConfig() + exitOnError(err) + + return restConfig +} + +func APIClient() kubernetes.Interface { + apiClient, err := kubernetes.NewForConfig(RestConfig()) + exitOnError(err) + + return apiClient +} diff --git a/go.mod b/go.mod index ae87e876c..25f68480a 100644 --- a/go.mod +++ b/go.mod @@ -52,6 +52,7 @@ require ( k8s.io/apimachinery v0.25.6 k8s.io/cli-runtime v0.25.6 k8s.io/client-go v0.25.6 + k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 k8s.io/klog/v2 v2.100.1 k8s.io/kubectl v0.25.6 k8s.io/utils v0.0.0-20221108210102-8e77b1f39fe2 @@ -139,8 +140,10 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.9.0 // indirect + golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect + golang.org/x/tools v0.9.1 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index e7846c52a..df85a30f0 100644 --- a/go.sum +++ b/go.sum @@ -822,6 +822,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1070,6 +1071,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1279,6 +1281,8 @@ k8s.io/component-base v0.25.6 h1:v3ci6FbXFcxpjyQJaaLq0MgzT3vyFzwUDWtO+KRv9Bk= k8s.io/component-base v0.25.6/go.mod h1:k7DfcfJ8cOI6A2xTCfU5LxsnXV+lWw1ME8cRCHzIh6o= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 h1:iu3o/SxaHVI7tKPtkGzD3M9IzrE21j+CUKH98NQJ8Ms= +k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=