From 09ae3b5c9a6e529c813269b246eddd62690a1fb8 Mon Sep 17 00:00:00 2001 From: Albert Zhong Date: Wed, 16 Sep 2020 17:33:59 -0700 Subject: [PATCH 1/2] Add more language flags, fix minor bugs --- Makefile | 2 +- cmd/root.go | 90 ++++++++++++++++++++++++-------- gen/dotnet.go | 28 ++++++---- gen/generate.go | 88 +++++++++++++++---------------- gen/golang.go | 29 +++++----- gen/language.go | 58 ++++++++++++++++++++ gen/nodejs.go | 73 +++----------------------- gen/python.go | 30 ++++++----- gen/schema.go | 72 +++++++++---------------- gen/utilities.go | 20 +++---- go.mod | 2 +- go.sum | 30 ++++++++++- tests/schema_test.go | 16 ------ tests/test-underscorefields.yaml | 69 ------------------------ 14 files changed, 286 insertions(+), 321 deletions(-) create mode 100644 gen/language.go delete mode 100644 tests/test-underscorefields.yaml diff --git a/Makefile b/Makefile index d7c1379..5780ca1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ PROJECT := github.com/pulumi/crd2pulumi -VERSION := 1.0.4 +VERSION := 1.0.5 LDFLAGS := "-X 'github.com/pulumi/crd2pulumi/gen.Version=$(VERSION)'" GO ?= go diff --git a/cmd/root.go b/cmd/root.go index e1ec421..c07bc40 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -39,7 +39,14 @@ const ( PythonPath string = "pythonPath" ) -var defaultOutputPath = "crds/" +const ( + DotNetName string = "dotnetName" + GoName string = "goName" + NodeJSName string = "nodejsName" + PythonName string = "pythonName" +) + +const defaultOutputPath = "crds/" const long = `crd2pulumi is a CLI tool that generates typed Kubernetes CustomResources to use in Pulumi programs, based on a @@ -53,7 +60,9 @@ Notice that by just setting a language-specific output path (--pythonPath, --nod still get generated, so setting -p, -n, etc becomes unnecessary. ` -func getLanguageSettings(flags *pflag.FlagSet) gen.LanguageSettings { +// NewLanguageSettings returns the parsed language settings given a set of flags. Also returns a list of notices for +// possibly misinterpreted flags. +func NewLanguageSettings(flags *pflag.FlagSet) (gen.LanguageSettings, []string) { nodejs, _ := flags.GetBool(NodeJS) python, _ := flags.GetBool(Python) dotnet, _ := flags.GetBool(DotNet) @@ -64,32 +73,55 @@ func getLanguageSettings(flags *pflag.FlagSet) gen.LanguageSettings { dotnetPath, _ := flags.GetString(DotNetPath) goPath, _ := flags.GetString(GoPath) - ls := gen.LanguageSettings{} + nodejsName, _ := flags.GetString(NodeJSName) + pythonName, _ := flags.GetString(PythonName) + dotNetName, _ := flags.GetString(DotNetName) + goName, _ := flags.GetString(GoName) + + var notices []string + ls := gen.LanguageSettings{ + NodeJSName: nodejsName, + PythonName: pythonName, + DotNetName: dotNetName, + GoName: goName, + } if nodejsPath != "" { ls.NodeJSPath = &nodejsPath - } else if nodejs { + if nodejs { + notices = append(notices, "-n is not necessary if --nodejsPath is already set") + } + } else if nodejs || nodejsName != gen.DefaultName { path := filepath.Join(defaultOutputPath, NodeJS) ls.NodeJSPath = &path } if pythonPath != "" { ls.PythonPath = &pythonPath - } else if python { + if python { + notices = append(notices, "-p is not necessary if --pythonPath is already set") + } + } else if python || pythonName != gen.DefaultName { path := filepath.Join(defaultOutputPath, Python) ls.PythonPath = &path } if dotnetPath != "" { ls.DotNetPath = &dotnetPath - } else if dotnet { + if dotnet { + notices = append(notices, "-d is not necessary if --dotnetPath is already set") + } + } else if dotnet || dotNetName != gen.DefaultName { path := filepath.Join(defaultOutputPath, DotNet) ls.DotNetPath = &path } if goPath != "" { ls.GoPath = &goPath - } else if golang { + if golang { + notices = append(notices, "-g is not necessary if --goPath is already set") + } + } else if golang || goName != gen.DefaultName{ path := filepath.Join(defaultOutputPath, Go) ls.GoPath = &path } - return ls + return ls, notices } var ( @@ -100,8 +132,7 @@ var ( Example: example, Version: gen.Version, Args: func(cmd *cobra.Command, args []string) error { - emptyLanguageSettings := gen.LanguageSettings{} - if getLanguageSettings(cmd.Flags()) == emptyLanguageSettings { + if ls, _ := NewLanguageSettings(cmd.Flags()); !ls.GeneratesAtLeastOneLanguage() { return errors.New("must specify at least one language") } @@ -114,9 +145,12 @@ var ( }, Run: func(cmd *cobra.Command, args []string) { force, _ := cmd.Flags().GetBool("force") - languageSettings := getLanguageSettings(cmd.Flags()) + ls, notices := NewLanguageSettings(cmd.Flags()) + for _, notice := range notices { + fmt.Println("notice: " + notice) + } - err := gen.Generate(languageSettings, args, force) + err := gen.Generate(ls, args, force) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(-1) @@ -134,17 +168,31 @@ func Execute() error { var forceValue bool var nodeJSValue, pythonValue, dotNetValue, goValue bool var nodeJSPathValue, pythonPathValue, dotNetPathValue, goPathValue string +var nodeJSNameValue, pythonNameValue, dotNetNameValue, goNameValue string func init() { - rootCmd.PersistentFlags().BoolVarP(&nodeJSValue, NodeJS, "n", false, "generate NodeJS") - rootCmd.PersistentFlags().BoolVarP(&pythonValue, Python, "p", false, "generate Python") - rootCmd.PersistentFlags().BoolVarP(&dotNetValue, DotNet, "d", false, "generate .NET") - rootCmd.PersistentFlags().BoolVarP(&goValue, Go, "g", false, "generate Go") + addBoolFlag := func(p *bool, name, shorthand string, value bool, usage string) { + rootCmd.PersistentFlags().BoolVarP(p, name, shorthand, value, usage) + } + + addBoolFlag(&forceValue, "force", "f", false, "overwrite existing files") + + addBoolFlag(&nodeJSValue, NodeJS, "n", false, "generate NodeJS") + addBoolFlag(&pythonValue, Python, "p", false, "generate Python") + addBoolFlag(&dotNetValue, DotNet, "d", false, "generate .NET") + addBoolFlag(&goValue, Go, "g", false, "generate Go") + + addStringFlag := func(p *string, name string, value string, usage string) { + rootCmd.PersistentFlags().StringVar(p, name, value, usage) + } - rootCmd.PersistentFlags().StringVar(&nodeJSPathValue, NodeJSPath, "", "optional NodeJS output dir") - rootCmd.PersistentFlags().StringVar(&pythonPathValue, PythonPath, "", "optional Python output dir") - rootCmd.PersistentFlags().StringVar(&dotNetPathValue, DotNetPath, "", "optional .NET output dir") - rootCmd.PersistentFlags().StringVar(&goPathValue, GoPath, "", "optional Go output dir") + addStringFlag(&nodeJSPathValue, NodeJSPath, "", "optional NodeJS output dir") + addStringFlag(&pythonPathValue, PythonPath, "", "optional Python output dir") + addStringFlag(&dotNetPathValue, DotNetPath, "", "optional .NET output dir") + addStringFlag(&goPathValue, GoPath, "", "optional Go output dir") - rootCmd.PersistentFlags().BoolVarP(&forceValue, "force", "f", false, "overwrite existing files") + addStringFlag(&nodeJSNameValue, NodeJSName, gen.DefaultName, "name of NodeJS package") + addStringFlag(&pythonNameValue, PythonName, gen.DefaultName, "name of Python package") + addStringFlag(&dotNetNameValue, DotNetName, gen.DefaultName, "name of .NET package") + addStringFlag(&goNameValue, GoName, gen.DefaultName, "name of Go package") } diff --git a/gen/dotnet.go b/gen/dotnet.go index 03a9c71..a09ae4a 100644 --- a/gen/dotnet.go +++ b/gen/dotnet.go @@ -30,8 +30,8 @@ var unneededDotNetFiles = []string{ "Provider.cs", } -func (pg *PackageGenerator) genDotNet(outputDir string) error { - if files, err := pg.genDotNetFiles(); err != nil { +func (pg *PackageGenerator) genDotNet(outputDir, name string) error { + if files, err := pg.genDotNetFiles(name); err != nil { return err } else if err := writeFiles(files, outputDir); err != nil { return err @@ -39,7 +39,7 @@ func (pg *PackageGenerator) genDotNet(outputDir string) error { return nil } -func (pg *PackageGenerator) genDotNetFiles() (map[string]*bytes.Buffer, error) { +func (pg *PackageGenerator) genDotNetFiles(name string) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() // Set up C# namespaces @@ -56,6 +56,8 @@ func (pg *PackageGenerator) genDotNetFiles() (map[string]*bytes.Buffer, error) { // class defined in the .NET SDK is located at // `Pulumi.Kubernetes.Types.Outputs.Meta.V1.ObjectMeta`. This path would // only get generated properly if `compatibility` was `kubernetes20`. + oldName := pkg.Name + pkg.Name = name pkg.Language["csharp"] = rawMessage(map[string]interface{}{ "packageReferences": map[string]string{ "Pulumi.Kubernetes": "2.*", @@ -70,10 +72,11 @@ func (pg *PackageGenerator) genDotNetFiles() (map[string]*bytes.Buffer, error) { return nil, errors.Wrap(err, "could not generate .NET package") } - delete(pkg.Language, "chsarp") + pkg.Name = oldName + delete(pkg.Language, "csharp") - files["KubernetesResource.cs"] = []byte(kubernetesResource) - files["Utilities.cs"] = []byte(dotNetUtilities) + files["KubernetesResource.cs"] = []byte(kubernetesResource(name)) + files["Utilities.cs"] = []byte(dotNetUtilities(name)) // Delete unneeded files for _, unneededFile := range unneededDotNetFiles { @@ -88,9 +91,9 @@ func (pg *PackageGenerator) genDotNetFiles() (map[string]*bytes.Buffer, error) { return buffers, nil } -var kubernetesResource = `// Copyright 2016-2020, Pulumi Corporation - -namespace Pulumi.` + strings.Title(packageName) + `{ +func kubernetesResource(name string) string { + return `// Copyright 2016-2020, Pulumi Corporation +namespace Pulumi.` + name + `{ /// /// A base class for all Kubernetes resources. /// @@ -114,19 +117,21 @@ namespace Pulumi.` + strings.Title(packageName) + `{ } } ` +} // For some reason, we get a `Missing embedded version.txt file` error if we // tried running `pulumi up` with the normal `Utilities.cs` file. // As a temporary fix, this modified `Utilities.cs` file just removes the // `static Utilities()` method. -var dotNetUtilities = `// *** WARNING: this file was generated by crd2pulumi. *** +func dotNetUtilities(name string) string { + return `// *** WARNING: this file was generated by crd2pulumi. *** // *** Do not edit by hand unless you're certain you know what you are doing! *** using System; using System.Reflection; using Pulumi.Kubernetes; -namespace Pulumi.` + strings.Title(packageName) + ` +namespace Pulumi.` + name + ` { static class Utilities { @@ -159,3 +164,4 @@ namespace Pulumi.` + strings.Title(packageName) + ` } } ` +} diff --git a/gen/generate.go b/gen/generate.go index e88760e..8ac1bbf 100644 --- a/gen/generate.go +++ b/gen/generate.go @@ -42,39 +42,7 @@ const ( ) // Version specifies the crd2pulumi version. It should be set by the linker via LDFLAGS. -var Version string - -// LanguageSettings contains the output paths for each language. If a path is -// null, then that language will not be generated at all. -type LanguageSettings struct { - NodeJSPath *string - PythonPath *string - DotNetPath *string - GoPath *string -} - -// Returns true if at least one of the language-specific output paths already exists. If true, then a slice of the -// paths that already exist are also returned. -func (ls LanguageSettings) hasExistingPaths() (bool, []string) { - pathExists := func(path string) bool { - _, err := os.Stat(path) - return !os.IsNotExist(err) - } - var existingPaths []string - if ls.NodeJSPath != nil && pathExists(*ls.NodeJSPath) { - existingPaths = append(existingPaths, *ls.NodeJSPath) - } - if ls.PythonPath != nil && pathExists(*ls.PythonPath) { - existingPaths = append(existingPaths, *ls.PythonPath) - } - if ls.DotNetPath != nil && pathExists(*ls.DotNetPath) { - existingPaths = append(existingPaths, *ls.DotNetPath) - } - if ls.GoPath != nil && pathExists(*ls.GoPath) { - existingPaths = append(existingPaths, *ls.GoPath) - } - return len(existingPaths) > 0, existingPaths -} +var Version string = "1.0.0" // Generate parses the CRDs at the given yamlPaths and outputs the generated // code according to the language settings. Only overwrites existing files if @@ -92,22 +60,22 @@ func Generate(ls LanguageSettings, yamlPaths []string, force bool) error { } if ls.NodeJSPath != nil { - if err := pg.genNodeJS(*ls.NodeJSPath); err != nil { + if err := pg.genNodeJS(*ls.NodeJSPath, ls.NodeJSName); err != nil { return err } } if ls.PythonPath != nil { - if err := pg.genPython(*ls.PythonPath); err != nil { + if err := pg.genPython(*ls.PythonPath, ls.PythonName); err != nil { return err } } if ls.GoPath != nil { - if err := pg.genGo(*ls.GoPath); err != nil { + if err := pg.genGo(*ls.GoPath, ls.GoName); err != nil { return err } } if ls.DotNetPath != nil { - if err := pg.genDotNet(*ls.DotNetPath); err != nil { + if err := pg.genDotNet(*ls.DotNetPath, ls.DotNetName); err != nil { return err } } @@ -171,6 +139,10 @@ func NewPackageGenerator(yamlPaths []string) (PackageGenerator, error) { return PackageGenerator{}, errors.Wrapf(err, "could not unmarshal yaml file(s)") } + if len(crds) == 0 { + return PackageGenerator{}, errors.New("could not find any CRD YAML files") + } + resourceTokensSize := 0 groupVersionsSize := 0 @@ -234,6 +206,16 @@ func (pg *PackageGenerator) moduleToPackage() map[string]string { return moduleToPackage } +// HasSchemas returns true if there exists at least one CustomResource with a schema in this package. +func (pg *PackageGenerator) HasSchemas() bool { + for _, crg := range pg.CustomResourceGenerators { + if crg.HasSchemas() { + return true + } + } + return false +} + // CustomResourceGenerator generates a Pulumi schema for a single CustomResource type CustomResourceGenerator struct { // CustomResourceDefinition contains the unmarshalled CRD YAML @@ -261,21 +243,28 @@ type CustomResourceGenerator struct { func NewCustomResourceGenerator(crd unstruct.Unstructured) (CustomResourceGenerator, error) { apiVersion := crd.GetAPIVersion() - schemas := map[string]map[string]interface{}{} + validation, foundValidation, _ := unstruct.NestedMap(crd.Object, "spec", "validation", "openAPIV3Schema") if foundValidation { // If present, use the top-level schema to validate all versions - versionMaps, _, _ := NestedMapSlice(crd.Object, "spec", "versions") - for _, version := range versionMaps { - name, _, _ := unstruct.NestedString(version, "name") - schemas[name] = validation + versionName, foundVersionName, _ := unstruct.NestedString(crd.Object, "spec", "version") + if foundVersionName { + schemas[versionName] = validation + } else if versionInfos, foundVersionInfos, _ := NestedMapSlice(crd.Object, "spec", "versions"); foundVersionInfos { + for _, versionInfo := range versionInfos { + versionName, _, _ := unstruct.NestedString(versionInfo, "name") + schemas[versionName] = validation + } } } else { // Otherwise use per-version schemas to validate each version - versionMaps, _, _ := NestedMapSlice(crd.Object, "spec", "versions") - for _, version := range versionMaps { - name, _, _ := unstruct.NestedString(version, "name") - schema, _, _ := unstruct.NestedMap(version, "schema", "openAPIV3Schema") - schemas[name] = schema + versionInfos, foundVersionInfos, _ := NestedMapSlice(crd.Object, "spec", "versions") + if foundVersionInfos { + for _, version := range versionInfos { + name, _, _ := unstruct.NestedString(version, "name") + if schema, foundSchema, _ := unstruct.NestedMap(version, "schema", "openAPIV3Schema"); foundSchema { + schemas[name] = schema + } + } } } @@ -316,6 +305,11 @@ func NewCustomResourceGenerator(crd unstruct.Unstructured) (CustomResourceGenera return crg, nil } +// HasSchemas returns true if the CustomResource specifies at least some schema, and false otherwise. +func (crg *CustomResourceGenerator) HasSchemas() bool { + return len(crg.Schemas) > 0 +} + // Returns the type token for a Kubernetes CustomResource with the given group, // version, and kind. func getToken(group, version, kind string) string { diff --git a/gen/golang.go b/gen/golang.go index 1f92bef..c38ac4a 100644 --- a/gen/golang.go +++ b/gen/golang.go @@ -16,20 +16,20 @@ package gen import ( "bytes" - "path/filepath" - "github.com/pkg/errors" + "github.com/pulumi/pulumi/pkg/v2/codegen" go_gen "github.com/pulumi/pulumi/pkg/v2/codegen/go" + "path/filepath" ) -var unneededGoFiles = []string{ +var unneededGoFiles = codegen.NewStringSet( "doc.go", "provider.go", "meta/v1/pulumiTypes.go", -} +) -func (pg *PackageGenerator) genGo(outputDir string) error { - if files, err := pg.genGoFiles(); err != nil { +func (pg *PackageGenerator) genGo(outputDir, name string) error { + if files, err := pg.genGoFiles(name); err != nil { return err } else if err := writeFiles(files, outputDir); err != nil { return err @@ -37,9 +37,11 @@ func (pg *PackageGenerator) genGo(outputDir string) error { return nil } -func (pg *PackageGenerator) genGoFiles() (map[string]*bytes.Buffer, error) { +func (pg *PackageGenerator) genGoFiles(name string) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() + oldName := pkg.Name + pkg.Name = name moduleToPackage := pg.moduleToPackage() moduleToPackage["meta/v1"] = "meta/v1" pkg.Language["go"] = rawMessage(map[string]interface{}{ @@ -55,21 +57,16 @@ func (pg *PackageGenerator) genGoFiles() (map[string]*bytes.Buffer, error) { return nil, errors.Wrap(err, "could not generate Go package") } + pkg.Name = oldName delete(pkg.Language, Go) buffers := map[string]*bytes.Buffer{} - // Now we remove the "crds/" file path prefix for path, code := range files { - newPath, err := filepath.Rel(packageName, path) - if err != nil { - return nil, errors.Wrapf(err, "could not remove \"crds/\" prefix") + newPath, _ := filepath.Rel(name, path) + if !unneededGoFiles.Has(newPath) { + buffers[newPath] = bytes.NewBuffer(code) } - buffers[newPath] = bytes.NewBuffer(code) - } - - for _, unneededFile := range unneededGoFiles { - delete(buffers, unneededFile) } return buffers, nil diff --git a/gen/language.go b/gen/language.go new file mode 100644 index 0000000..11e0fa3 --- /dev/null +++ b/gen/language.go @@ -0,0 +1,58 @@ +// Copyright 2016-2020, Pulumi Corporation. +// +// Licensed 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 gen + +import "os" + +// LanguageSettings containers the output paths and package names for each language. +// If a path field is nil, the language won't be generated at all. +type LanguageSettings struct { + NodeJSPath *string + PythonPath *string + DotNetPath *string + GoPath *string + NodeJSName string + PythonName string + DotNetName string + GoName string +} + +// Returns true if at least one of the language-specific output paths already exists. If true, then a slice of the +// paths that already exist are also returned. +func (ls LanguageSettings) hasExistingPaths() (bool, []string) { + pathExists := func(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) + } + var existingPaths []string + if ls.NodeJSPath != nil && pathExists(*ls.NodeJSPath) { + existingPaths = append(existingPaths, *ls.NodeJSPath) + } + if ls.PythonPath != nil && pathExists(*ls.PythonPath) { + existingPaths = append(existingPaths, *ls.PythonPath) + } + if ls.DotNetPath != nil && pathExists(*ls.DotNetPath) { + existingPaths = append(existingPaths, *ls.DotNetPath) + } + if ls.GoPath != nil && pathExists(*ls.GoPath) { + existingPaths = append(existingPaths, *ls.GoPath) + } + return len(existingPaths) > 0, existingPaths +} + +// GeneratesAtLeastOneLanguage returns true if and only if at least one language would be generated. +func (ls LanguageSettings) GeneratesAtLeastOneLanguage() bool { + return ls.NodeJSPath != nil || ls.PythonPath != nil || ls.DotNetPath != nil || ls.GoPath != nil +} diff --git a/gen/nodejs.go b/gen/nodejs.go index e4a88a4..4edb360 100644 --- a/gen/nodejs.go +++ b/gen/nodejs.go @@ -16,13 +16,8 @@ package gen import ( "bytes" - "encoding/json" - "fmt" - "path/filepath" - "github.com/pkg/errors" "github.com/pulumi/pulumi/pkg/v2/codegen/nodejs" - "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" ) const nodejsMetaPath = "meta/v1.ts" @@ -31,8 +26,8 @@ const nodejsMetaFile = `import * as k8s from "@pulumi/kubernetes"; export type ObjectMeta = k8s.types.input.meta.v1.ObjectMeta; ` -func (pg *PackageGenerator) genNodeJS(outputDir string) error { - if files, err := pg.genNodeJSFiles(); err != nil { +func (pg *PackageGenerator) genNodeJS(outputDir string, name string) error { + if files, err := pg.genNodeJSFiles(name); err != nil { return err } else if err := writeFiles(files, outputDir); err != nil { return err @@ -40,9 +35,11 @@ func (pg *PackageGenerator) genNodeJS(outputDir string) error { return nil } -func (pg *PackageGenerator) genNodeJSFiles() (map[string]*bytes.Buffer, error) { +func (pg *PackageGenerator) genNodeJSFiles(name string) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackage() + oldName := pkg.Name + pkg.Name = name pkg.Language["nodejs"] = rawMessage(map[string]interface{}{ "moduleToPackage": pg.moduleToPackage(), }) @@ -52,6 +49,7 @@ func (pg *PackageGenerator) genNodeJSFiles() (map[string]*bytes.Buffer, error) { return nil, errors.Wrap(err, "could not generate nodejs package") } + pkg.Name = oldName delete(pkg.Language, NodeJS) // Remove ${VERSION} in package.json @@ -74,64 +72,5 @@ func (pg *PackageGenerator) genNodeJSFiles() (map[string]*bytes.Buffer, error) { buffers[name] = bytes.NewBuffer(code) } - // Generates CustomResourceDefinition constructors. Soon this will be - // replaced with `kube2pulumi` - for _, crg := range pg.CustomResourceGenerators { - if !IsValidAPIVersion(crg.APIVersion) { - continue - } - - definitionFileName := toLowerFirst(crg.Kind) + "Definition" - - // Create the customResourceDefinition.ts class - path := filepath.Join(groupPrefix(crg.Group), definitionFileName+".ts") - _, ok := buffers[path] - contract.Assertf(!ok, "duplicate file at %s", path) - buffer := &bytes.Buffer{} - crg.genNodeJSDefinition(buffer) - buffers[path] = buffer - - // Export in the index.ts file - indexPath := filepath.Join(filepath.Dir(path), "index.ts") - indexBuffer := buffers[indexPath] - definitionClassName := crg.Kind + "Definition" - exportCode := fmt.Sprintf( - "import {%s} from \"./%s\";\nexport {%s};\n", - definitionClassName, - definitionFileName, - definitionClassName, - ) - indexBuffer.WriteString(exportCode) - } - return buffers, nil } - -const definitionImports = `import * as pulumi from "@pulumi/pulumi"; -import * as k8s from "@pulumi/kubernetes"; - -` - -// Outputs the code for a CustomResourceDefinition class to the given buffer. -// Mutates crg.CustomResourceDefinition.Object by underscoring all hyphenated -// fields. -func (crg *CustomResourceGenerator) genNodeJSDefinition(buffer *bytes.Buffer) { - className := crg.Kind + "Definition" - var superClassName string - if crg.APIVersion == v1 { - superClassName = "k8s.apiextensions.v1.CustomResourceDefinition" - } else { - superClassName = "k8s.apiextensions.v1beta1.CustomResourceDefinition" - } - - fmt.Fprint(buffer, definitionImports) - fmt.Fprintf(buffer, "export class %s extends %s {\n", className, superClassName) - fmt.Fprint(buffer, "\tconstructor(name: string, opts?: pulumi.CustomResourceOptions) {\n") - fmt.Fprint(buffer, "\t\tsuper(name, ") - - UnderscoreFields(crg.CustomResourceDefinition.Object) - definitionArgs, _ := json.MarshalIndent(crg.CustomResourceDefinition.Object, "\t\t", "\t") - buffer.Write(definitionArgs) - - fmt.Fprint(buffer, ", opts)\n\t}\n}\n") -} diff --git a/gen/python.go b/gen/python.go index 924742a..30f614d 100644 --- a/gen/python.go +++ b/gen/python.go @@ -23,18 +23,12 @@ import ( "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" ) -const pythonPackageDir = "pulumi_" + packageName const pythonMetaFile = `from pulumi_kubernetes.meta.v1._inputs import * import pulumi_kubernetes.meta.v1.outputs ` -var unneededPythonFiles = []string{ - filepath.Join(pythonPackageDir, "README.md"), - "setup.py", -} - -func (pg *PackageGenerator) genPython(outputDir string) error { - if files, err := pg.genPythonFiles(); err != nil { +func (pg *PackageGenerator) genPython(outputDir, name string) error { + if files, err := pg.genPythonFiles(name); err != nil { return err } else if err := writeFiles(files, outputDir); err != nil { return err @@ -42,9 +36,11 @@ func (pg *PackageGenerator) genPython(outputDir string) error { return nil } -func (pg *PackageGenerator) genPythonFiles() (map[string]*bytes.Buffer, error) { +func (pg *PackageGenerator) genPythonFiles(name string) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() + oldName := pkg.Name + pkg.Name = name pkg.Language[Python] = rawMessage(map[string]interface{}{ "compatibility": "kubernetes20", "moduleNameOverrides": pg.moduleToPackage(), @@ -61,9 +57,15 @@ func (pg *PackageGenerator) genPythonFiles() (map[string]*bytes.Buffer, error) { return nil, errors.Wrap(err, "could not generate Go package") } + pkg.Name = oldName delete(pkg.Language, Python) + pythonPackageDir := "pulumi_" + name + // Remove unneeded files + var unneededPythonFiles = []string{ + filepath.Join(pythonPackageDir, "README.md"), + } for _, unneededFile := range unneededPythonFiles { delete(files, unneededFile) } @@ -75,10 +77,12 @@ func (pg *PackageGenerator) genPythonFiles() (map[string]*bytes.Buffer, error) { files[utilitiesPath] = []byte(pythonUtilitiesFile) // Import the actual SDK ObjectMeta types in place of our placeholder ones - metaPath := filepath.Join(pythonPackageDir, "meta_v1", "__init__.py") - code, ok := files[metaPath] - contract.Assertf(ok, "missing meta_v1/__init__.py file") - files[metaPath] = append(code, []byte(pythonMetaFile)...) + if pg.HasSchemas() { + metaPath := filepath.Join(pythonPackageDir, "meta_v1", "__init__.py") + code, ok := files[metaPath] + contract.Assertf(ok, "missing meta_v1/__init__.py file") + files[metaPath] = append(code, []byte(pythonMetaFile)...) + } buffers := map[string]*bytes.Buffer{} for name, code := range files { diff --git a/gen/schema.go b/gen/schema.go index ba3ee81..92e775b 100644 --- a/gen/schema.go +++ b/gen/schema.go @@ -19,14 +19,23 @@ import ( "strings" "github.com/pkg/errors" - "github.com/pulumi/pulumi/pkg/v2/codegen" pschema "github.com/pulumi/pulumi/pkg/v2/codegen/schema" unstruct "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -const packageName = "crds" +// DefaultName specifies the default value for the package name +const DefaultName = "crds" const tool = "crd2pulumi" +const ( + Boolean string = "boolean" + Integer string = "integer" + Number string = "number" + String string = "string" + Array string = "array" + Object string = "object" +) + const anyTypeRef = "pulumi.json#/Any" var anyTypeSpec = pschema.TypeSpec{ @@ -37,39 +46,40 @@ var arbitraryJSONTypeSpec = pschema.TypeSpec{ AdditionalProperties: &anyTypeSpec, } +var emptyObjectSpec = pschema.ObjectTypeSpec{ + Type: Object, + Properties: map[string]pschema.PropertySpec{}, +} + const objectMetaRef = "#/types/kubernetes:meta/v1:ObjectMeta" const objectMetaToken = "kubernetes:meta/v1:ObjectMeta" // Union type of integer and string var intOrStringTypeSpec = pschema.TypeSpec{ OneOf: []pschema.TypeSpec{ - pschema.TypeSpec{ + { Type: Integer, }, - pschema.TypeSpec{ + { Type: String, }, }, } -const ( - Boolean string = "boolean" - Integer string = "integer" - Number string = "number" - String string = "string" - Array string = "array" - Object string = "object" -) - func (pg *PackageGenerator) GetTypes() map[string]pschema.ObjectTypeSpec { types := map[string]pschema.ObjectTypeSpec{} - for _, crg := range pg.CustomResourceGenerators { for version, schema := range crg.Schemas { resourceToken := getToken(crg.Group, version, crg.Kind) _, foundProperties, _ := unstruct.NestedMap(schema, "properties") if foundProperties { AddType(schema, resourceToken, types) + } + preserveUnknownFields, _, _ := unstruct.NestedBool(schema, "x-kubernetes-preserve-unknown-fields") + if preserveUnknownFields { + types[resourceToken] = emptyObjectSpec + } + if foundProperties || preserveUnknownFields { types[resourceToken].Properties["apiVersion"] = pschema.PropertySpec{ TypeSpec: pschema.TypeSpec{ Type: String, @@ -90,7 +100,6 @@ func (pg *PackageGenerator) GetTypes() map[string]pschema.ObjectTypeSpec { } } } - return types } @@ -114,7 +123,7 @@ func genPackage(types map[string]pschema.ObjectTypeSpec, resourceTokens []string } pkgSpec := pschema.PackageSpec{ - Name: packageName, + Name: DefaultName, Version: Version, Types: types, Resources: resources, @@ -325,34 +334,3 @@ func CombineSchemas(combineRequired bool, schemas ...map[string]interface{}) map } return combinedSchema } - -// hyphenedFields contains a set of the hyphened Kubernetes fields -var hyphenedFields = codegen.NewStringSet( - "x-kubernetes-embedded-resource", - "x-kubernetes-int-or-string", - "x-kubernetes-list-map-keys", - "x-kubernetes-list-type", - "x-kubernetes-map-type", - "x-kubernetes-preserve-unknown-fields", -) - -// UnderscoreFields replaces all hyphens in key names with underscores if the -// key name is in the `hyphenedFields` set. -func UnderscoreFields(schema map[string]interface{}) { - for field, val := range schema { - if hyphenedFields.Has(field) { - delete(schema, field) - underScoredField := strings.ReplaceAll(field, "-", "_") - schema[underScoredField] = val - } - if subSchema, ok := val.(map[string]interface{}); ok { - UnderscoreFields(subSchema) - } else if subSchemaSlice, ok := val.([]interface{}); ok { - for _, genericSubSchema := range subSchemaSlice { - if subSchema, ok = genericSubSchema.(map[string]interface{}); ok { - UnderscoreFields(subSchema) - } - } - } - } -} diff --git a/gen/utilities.go b/gen/utilities.go index 5a15b4e..a245ba1 100644 --- a/gen/utilities.go +++ b/gen/utilities.go @@ -30,30 +30,30 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" ) -// UnmarshalYamls unmarshals the YAML documents in the given file into a slice -// of unstruct.Unstructureds, one for each CRD. Returns an error if any +const CRD = "CustomResourceDefinition" + +// UnmarshalYamls un-marshals the YAML documents in the given file into a slice of unstruct.Unstructureds, one for each +// CRD. Only returns the YAML files for Kubernetes manifests that are CRDs and ignores others. Returns an error if any // document failed to unmarshal. func UnmarshalYamls(yamlFiles [][]byte) ([]unstruct.Unstructured, error) { - var err error var crds []unstruct.Unstructured - for _, yamlFile := range yamlFiles { + var err error dec := yaml.NewYAMLOrJSONDecoder(ioutil.NopCloser(bytes.NewReader(yamlFile)), 128) for err != io.EOF { var value map[string]interface{} if err = dec.Decode(&value); err != nil && err != io.EOF { return nil, errors.Wrap(err, "failed to unmarshal yaml") } - if value != nil { - crds = append(crds, unstruct.Unstructured{Object: value}) + if crd := (unstruct.Unstructured{Object: value}); value != nil && crd.GetKind() == CRD { + crds = append(crds, crd) } } } - return crds, nil } -// UnmarshalYaml unmarshals one and only one YAML document from a file +// UnmarshalYaml un-marshals one and only one YAML document from a file func UnmarshalYaml(yamlFile []byte) (map[string]interface{}, error) { dec := yaml.NewYAMLOrJSONDecoder(ioutil.NopCloser(bytes.NewReader(yamlFile)), 128) var value map[string]interface{} @@ -91,9 +91,9 @@ func jsonPath(fields []string) string { } func rawMessage(v interface{}) json.RawMessage { - bytes, err := json.Marshal(v) + rawBytes, err := json.Marshal(v) contract.Assert(err == nil) - return bytes + return rawBytes } var alphanumericRegex = regexp.MustCompile("[^a-zA-Z0-9]+") diff --git a/go.mod b/go.mod index 55329c3..11dcdac 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/pkg/errors v0.9.1 - github.com/pulumi/pulumi/pkg/v2 v2.9.3-0.20200902232519-69c57f8b47d1 + github.com/pulumi/pulumi/pkg/v2 v2.10.1 github.com/pulumi/pulumi/sdk/v2 v2.9.2 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index 3b2d9e8..c0e35a3 100644 --- a/go.sum +++ b/go.sum @@ -82,9 +82,11 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko github.com/Sirupsen/logrus v1.0.5/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U= github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= @@ -92,6 +94,7 @@ github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -111,6 +114,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -142,8 +146,10 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -151,6 +157,7 @@ github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSG github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -168,6 +175,7 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= @@ -211,6 +219,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= @@ -299,12 +308,17 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -312,6 +326,7 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= @@ -319,6 +334,7 @@ github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -383,10 +399,10 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/pulumi/pulumi-kubernetes v1.6.0 h1:PDo9O8G1JXQgkz22poKg6XjrCID7EH6IUjMQtbK5Dy8= -github.com/pulumi/pulumi-kubernetes/provider/v2 v2.0.0 h1:+k3grLYefSxFxDJkGv89NRYMGfzSbXv6bpiml+FOsik= github.com/pulumi/pulumi/pkg/v2 v2.9.3-0.20200902232519-69c57f8b47d1 h1:yVYnGMkSYK0JcPvMbM3fcIBJ8yUUIpz/PKT1q6DYYPo= github.com/pulumi/pulumi/pkg/v2 v2.9.3-0.20200902232519-69c57f8b47d1/go.mod h1:zQWe2D4tYJDeXNzSclqNmP8/SMSKOh8k22AbWg3+mVc= +github.com/pulumi/pulumi/pkg/v2 v2.10.1 h1:WrGKKFr8R0XqlKwcq4Bz0iG+PrxZ/fp0jJ/bWwurMUw= +github.com/pulumi/pulumi/pkg/v2 v2.10.1/go.mod h1:zQWe2D4tYJDeXNzSclqNmP8/SMSKOh8k22AbWg3+mVc= github.com/pulumi/pulumi/sdk/v2 v2.2.1/go.mod h1:QNbWpL4gvf3X0lUFT7TXA2Jo1ff/Ti2l97AyFGYwvW4= github.com/pulumi/pulumi/sdk/v2 v2.9.2 h1:3XrlU68YR4G+9oHbANSj1fhUfeC+NVLeMNtA7YEHVpE= github.com/pulumi/pulumi/sdk/v2 v2.9.2/go.mod h1:x84WPiFiuE+G4kJ5jUYkOxmnQJlWoJaHNeEYdqnCKA4= @@ -396,8 +412,11 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/ryboe/q v1.0.12 h1:Ehx4fAUEaZ5KW9Cf9w+ShQ41r5Znc5076jPdnqbfZ3o= +github.com/ryboe/q v1.0.12/go.mod h1:6xM6Lm3ZAh5H8d85zLohckSJcqIjJspf1gGkWWS8YGs= github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0= github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -503,6 +522,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -511,6 +531,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -659,9 +680,11 @@ golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200608174601-1b747fd94509 h1:MI14dOfl3OG6Zd32w3ugsrvcUO810fDZdWakTq39dH4= golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -748,7 +771,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -758,6 +783,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= diff --git a/tests/schema_test.go b/tests/schema_test.go index 37dc642..e0d2cc8 100644 --- a/tests/schema_test.go +++ b/tests/schema_test.go @@ -25,7 +25,6 @@ import ( "github.com/stretchr/testify/assert" ) -const TestUnderscoreFieldsYAML = "test-underscorefields.yaml" const TestCombineSchemasYAML = "test-combineschemas.yaml" const TestGetTypeSpecYAML = "test-gettypespec.yaml" const TestGetTypeSpecJSON = "test-gettypespec.json" @@ -55,21 +54,6 @@ func UnmarshalTypeSpecJSON(jsonPath string) (map[string]pschema.TypeSpec, error) return v, nil } -func TestUnderscoreFields(t *testing.T) { - schemas, err := UnmarshalSchemas(TestUnderscoreFieldsYAML) - assert.NoError(t, err) - - // Test that calling underscoreFields() on each initial schema changes it - // to become the same as the expected schema - for name := range schemas { - schema := schemas[name].(map[string]interface{}) - expected := schema["expected"].(map[string]interface{}) - initial := schema["initial"].(map[string]interface{}) - gen.UnderscoreFields(initial) - assert.EqualValues(t, expected, initial) - } -} - func TestCombineSchemas(t *testing.T) { // Test that CombineSchemas on no schemas returns nil assert.Nil(t, gen.CombineSchemas(false)) diff --git a/tests/test-underscorefields.yaml b/tests/test-underscorefields.yaml deleted file mode 100644 index 6be3afb..0000000 --- a/tests/test-underscorefields.yaml +++ /dev/null @@ -1,69 +0,0 @@ -empty: - initial: {} - expected: {} -noHyphens: - initial: - field1: true - field2: false - description: this-is-a-description - expected: - field1: true - field2: false - description: this-is-a-description -firstLevelHyphens: - initial: - x-kubernetes-embedded-resource: true - x-kubernetes-int-or-string: true - x-kubernetes-list-map-keys: true - x-kubernetes-list-type: true - x-kubernetes-map-type: true - x-kubernetes-preserve-unknown-fields: true - expected: - x_kubernetes_embedded_resource: true - x_kubernetes_int_or_string: true - x_kubernetes_list_map_keys: true - x_kubernetes_list_type: true - x_kubernetes_map_type: true - x_kubernetes_preserve_unknown_fields: true -nestedMapHyhens: - initial: - field1: true - field2: false - field3: - x-kubernetes-embedded-resource: true - x-kubernetes-int-or-string: true - x-kubernetes-list-map-keys: true - x-kubernetes-list-type: true - x-kubernetes-map-type: true - x-kubernetes-preserve-unknown-fields: true - expected: - field1: true - field2: false - field3: - x_kubernetes_embedded_resource: true - x_kubernetes_int_or_string: true - x_kubernetes_list_map_keys: true - x_kubernetes_list_type: true - x_kubernetes_map_type: true - x_kubernetes_preserve_unknown_fields: true -nestedMapSliceHyphens: - initial: - field1: true - field2: false - field3: - - x-kubernetes-embedded-resource: true - - x-kubernetes-int-or-string: true - - x-kubernetes-list-map-keys: true - - x-kubernetes-list-type: true - - x-kubernetes-map-type: true - - x-kubernetes-preserve-unknown-fields: true - expected: - field1: true - field2: false - field3: - - x_kubernetes_embedded_resource: true - - x_kubernetes_int_or_string: true - - x_kubernetes_list_map_keys: true - - x_kubernetes_list_type: true - - x_kubernetes_map_type: true - - x_kubernetes_preserve_unknown_fields: true From 5d78055dfb0b3eb94ca523e70ea231e6c3185733 Mon Sep 17 00:00:00 2001 From: stack72 Date: Thu, 17 Sep 2020 13:33:11 +0100 Subject: [PATCH 2/2] Adding the work to move us to Github Actions --- .github/workflows/ci.yml | 23 +++++++++++++ .github/workflows/release.yml | 24 +++++++++++++ .gitignore | 3 +- .goreleaser.yml | 35 +++++++++++++++++++ Makefile | 21 ----------- README.md | 65 +++++++++++++++++++++++++---------- main.go | 6 +++- 7 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .goreleaser.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..721906b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: ci +on: + pull_request: + branches: + - master + push: + branches: + - master +jobs: + ci: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Go 1.14 + uses: actions/setup-go@v2 + with: + go-version: '1.14.x' + - name: Run Go Build + run: go build main.go + - name: Run tests + run: go test -v . + working-directory: tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..718fdff --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +name: release +on: + push: + tags: [ "v*.[0-99]" ] # only a valid semver tag + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Unshallow clone + run: git fetch --prune --unshallow --tags + - name: Install Go 1.14 + uses: actions/setup-go@v2 + with: + go-version: '1.14.x' + - name: Goreleaser publish + uses: goreleaser/goreleaser-action@v1 + with: + version: v0.134.0 + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }} diff --git a/.gitignore b/.gitignore index eed44cf..d35a10e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_STORE .idea/ -releases/ \ No newline at end of file +releases/ +main diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..479b880 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,35 @@ +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + ldflags: + - -X github.com/pulumi/crd2pulumi/gen.Version={{.Tag}} + goarch: + - amd64 + binary: crd2pulumi + main: ./main.go +archives: + - name_template: "{{ .Binary }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}" + format_overrides: + - goos: windows + format: zip +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + skip: true +brews: + - + name: crd2pulumi + github: + owner: pulumi + name: homebrew-tap + commit_author: + name: pulumi-bot + email: bot@pulumi.com + homepage: "https://pulumi.com" + description: "Generate typed CustomResources in Pulumi from Kubernetes CRDs" diff --git a/Makefile b/Makefile index 5780ca1..2642b3e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,4 @@ PROJECT := github.com/pulumi/crd2pulumi -VERSION := 1.0.5 -LDFLAGS := "-X 'github.com/pulumi/crd2pulumi/gen.Version=$(VERSION)'" GO ?= go GOMODULE = GO111MODULE=on @@ -10,22 +8,3 @@ ensure:: build:: $(GOMODULE) $(GO) build $(PROJECT) - -release: rel-darwin rel-linux rel-windows - -rel-darwin:: - GOOS=darwin GOARCH=amd64 $(GO) build -ldflags=$(LDFLAGS) -o releases/crd2pulumi-darwin-amd64/crd2pulumi $(PROJECT) - tar -zcvf releases/crd2pulumi-darwin-amd64.tar.gz -C releases/crd2pulumi-darwin-amd64 . - -rel-linux:: - GOOS=linux GOARCH=386 $(GO) build -ldflags=$(LDFLAGS) -o releases/crd2pulumi-linux-386/crd2pulumi $(PROJECT) - tar -zcvf releases/crd2pulumi-linux-386.tar.gz -C releases/crd2pulumi-linux-386 . - GOOS=linux GOARCH=amd64 $(GO) build -ldflags=$(LDFLAGS) -o releases/crd2pulumi-linux-amd64/crd2pulumi $(PROJECT) - tar -zcvf releases/crd2pulumi-linux-amd64.tar.gz -C releases/crd2pulumi-linux-amd64 . - -rel-windows:: - GOOS=windows GOARCH=386 $(GO) build -ldflags=$(LDFLAGS) -o releases/crd2pulumi-windows-386/crd2pulumi.exe $(PROJECT) - zip -j releases/crd2pulumi-windows-386.zip releases/crd2pulumi-windows-386/crd2pulumi.exe - GOOS=windows GOARCH=amd64 $(GO) build -ldflags=$(LDFLAGS) -o releases/crd2pulumi-windows-amd64/crd2pulumi.exe $(PROJECT) - zip -j releases/crd2pulumi-windows-amd64.zip releases/crd2pulumi-windows-amd64/crd2pulumi.exe - diff --git a/README.md b/README.md index 8df5b07..86cc94d 100644 --- a/README.md +++ b/README.md @@ -3,48 +3,75 @@ Generate typed CustomResources based on Kubernetes CustomResourceDefinitions. ## Goals -`crd2pulumi` is a CLI tool that generates typed CustomResources based on Kubernetes CustomResourceDefinition (CRDs). CRDs allow you to extend the Kubernetes API by defining your own schemas for custom objects. While Pulumi lets you create [CustomResources](https://www.pulumi.com/docs/reference/pkg/kubernetes/apiextensions/customresource/), there was previously no strong-typing for these objects since every schema was, well, custom. This can be a massive headache for popular CRDs such as [cert-manager](https://github.com/jetstack/cert-manager/tree/master/deploy/crds) or [istio](https://github.com/istio/istio/tree/0321da58ca86fc786fb03a68afd29d082477e4f2/manifests/charts/base/crds), which contain thousands of lines of complex YAML schemas. By generating typed versions of CustomResources, `crd2pulumi` makes filling out their arguments more convenient by allowing you to leverage existing IDE type checking and autocomplete features. +`crd2pulumi` is a CLI tool that generates typed CustomResources based on Kubernetes CustomResourceDefinition (CRDs). +CRDs allow you to extend the Kubernetes API by defining your own schemas for custom objects. While Pulumi lets you create + [CustomResources](https://www.pulumi.com/docs/reference/pkg/kubernetes/apiextensions/customresource/), there was previously + no strong-typing for these objects since every schema was, well, custom. This can be a massive headache for popular CRDs + such as [cert-manager](https://github.com/jetstack/cert-manager/tree/master/deploy/crds) or + [istio](https://github.com/istio/istio/tree/0321da58ca86fc786fb03a68afd29d082477e4f2/manifests/charts/base/crds), which + contain thousands of lines of complex YAML schemas. By generating typed versions of CustomResources, `crd2pulumi` makes + filling out their arguments more convenient by allowing you to leverage existing IDE type checking and autocomplete features. ## Building and Installation If you wish to use `crd2pulumi` without developing the tool itself, you can use one of the [binary releases](https://github.com/pulumi/crd2pulumi/releases) hosted on this repository. -`crd2pulumi` uses Go modules to manage dependencies. If you want to develop `crd2pulumi` itself, you'll need to have Go installed in order to build. Once you install this prerequisite, run the following to build the `crd2pulumi` binary and install it into `$GOPATH/bin`: +### Homebrew +`crd2pulumi` can be installed on Mac from the Pulumi Homebrew tap. +```console +brew install pulumi/tap/crd2pulumi +``` + +`crd2pulumi` uses Go modules to manage dependencies. If you want to develop `crd2pulumi` itself, you'll need to have +Go installed in order to build. Once you install this prerequisite, run the following to build the `crd2pulumi` binary +and install it into `$GOPATH/bin`: ```bash -$ go build -ldflags="-X 'github.com/pulumi/crd2pulumi/gen.Version=1.0.0'" -o $GOPATH/bin/crd2pulumi main.go +$ go build -ldflags="-X github.com/pulumi/crd2pulumi/gen.Version=dev" -o $GOPATH/bin/crd2pulumi main.go ``` -The `ldflags` argument is necessary to dynamically set the `crd2pulumi` version at build time. However, the version -itself can be anything, so you don't have to set it to `1.0.0`. +The `ldflags` argument is necessary to dynamically set the `crd2pulumi` version at build time. However, the version +itself can be anything, so you don't have to set it to `dev`. -Go should then automatically handle pulling the dependencies for you. If `$GOPATH/bin` is not on your path, you may want to move the `crd2pulumi` binary from `$GOPATH/bin` into a directory that is on your path. +Go should then automatically handle pulling the dependencies for you. If `$GOPATH/bin` is not on your path, you may +want to move the `crd2pulumi` binary from `$GOPATH/bin` into a directory that is on your path. ## Usage ```bash -crd2pulumi [-dgnp] [--nodejsPath path] [--pythonPath path] [--dotnetPath path] [--goPath path] [crd2.yaml ...] [--force] +crd2pulumi is a CLI tool that generates typed Kubernetes +CustomResources to use in Pulumi programs, based on a +CustomResourceDefinition YAML schema. + +Usage: + crd2pulumi [-dgnp] [--nodejsPath path] [--pythonPath path] [--dotnetPath path] [--goPath path] [crd2.yaml ...] [flags] + +Examples: +crd2pulumi --nodejs crontabs.yaml +crd2pulumi -dgnp crd-certificates.yaml crd-issuers.yaml crd-challenges.yaml +crd2pulumi --pythonPath=crds/python/istio --nodejsPath=crds/nodejs/istio crd-all.gen.yaml crd-mixer.yaml crd-operator.yaml + +Notice that by just setting a language-specific output path (--pythonPath, --nodejsPath, etc) the code will +still get generated, so setting -p, -n, etc becomes unnecessary. -Example usage: -$ crd2pulumi --nodejs crontabs.yaml -$ crd2pulumi -dgnp crd-certificates.yaml crd-issuers.yaml crd-challenges.yaml -$ crd2pulumi --pythonPath=crds/python/istio --nodejsPath=crds/nodejs/istio crd-all.gen.yaml crd-mixer.yaml crd-operator.yaml Flags: -d, --dotnet generate .NET --dotnetPath string optional .NET output dir + -f, --force overwrite existing files -g, --go generate Go --goPath string optional Go output dir + -h, --help help for crd2pulumi -n, --nodejs generate NodeJS --nodejsPath string optional NodeJS output dir -p, --python generate Python --pythonPath string optional Python output dir - - -f, --force overwrite existing files - -v, --version version for crd2pulumi - -h, --help help for crd2pulumi ``` -Setting only a language-specific flag will output the generated code in the default directory; so `-d` will output to `crds/dotnet`, `-g` will output to `crds/go`, `-n` will output to `crds/nodejs`, and `-p` will output to `crds/python`. You can also specify a language-specific path (`--pythonPath`, `--nodejsPath`, etc) to control where the code will be outputted, in which case setting `-p`, `-n`, etc becomes unnecessary. +Setting only a language-specific flag will output the generated code in the default directory; so `-d` will output to +`crds/dotnet`, `-g` will output to `crds/go`, `-n` will output to `crds/nodejs`, and `-p` will output to `crds/python`. +You can also specify a language-specific path (`--pythonPath`, `--nodejsPath`, etc) to control where the code will be +outputted, in which case setting `-p`, `-n`, etc becomes unnecessary. ## Examples -Let's use the example CronTab CRD specified in `resourcedefinition.yaml` from the [Kubernetes Documentation](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/). +Let's use the example CronTab CRD specified in `resourcedefinition.yaml` from the +[Kubernetes Documentation](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/). ### TypeScript To generate a strongly-typed CronTab CustomResource in TypeScript, we can run this command: @@ -105,7 +132,9 @@ crontab_instance = crontabs.stable.v1.CronTab( ```bash $ crd2pulumi --goPath ./crontabs resourcedefinition.yaml ``` -Now we can access the `NewCronTab()` constructor. Create a `main.go` file with the following code. In this example, the Pulumi project's module is named `crds-go-final`, so the import path is `crds-go-final/crontabs/stable/v1`. Make sure to swap this out with your own module's name. +Now we can access the `NewCronTab()` constructor. Create a `main.go` file with the following code. In this example, +the Pulumi project's module is named `crds-go-final`, so the import path is `crds-go-final/crontabs/stable/v1`. Make +sure to swap this out with your own module's name. ```go package main diff --git a/main.go b/main.go index f984f17..1a814f8 100644 --- a/main.go +++ b/main.go @@ -15,12 +15,16 @@ package main import ( + "fmt" + "os" + "github.com/pulumi/crd2pulumi/cmd" ) func main() { err := cmd.Execute() if err != nil { - panic(err) + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(-1) } }