mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Merge pull request #2911 from phanimarupaka/SetWithSubPackages
Setters/substitutions with subpackages
This commit is contained in:
@@ -18,4 +18,4 @@ require (
|
|||||||
sigs.k8s.io/kustomize/kyaml v0.7.1
|
sigs.k8s.io/kustomize/kyaml v0.7.1
|
||||||
)
|
)
|
||||||
|
|
||||||
replace sigs.k8s.io/kustomize/kyaml v0.7.1 => ../../kyaml
|
replace sigs.k8s.io/kustomize/kyaml => ../../kyaml
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-openapi/spec"
|
"github.com/go-openapi/spec"
|
||||||
@@ -13,9 +15,9 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/pathutil"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||||
)
|
)
|
||||||
@@ -59,6 +61,8 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
|
|||||||
set.Flags().StringVar(&r.SchemaPath, "schema-path", "",
|
set.Flags().StringVar(&r.SchemaPath, "schema-path", "",
|
||||||
`openAPI schema file path for setter constraints -- file content `+
|
`openAPI schema file path for setter constraints -- file content `+
|
||||||
`e.g. {"type": "string", "maxLength": 15, "enum": ["allowedValue1", "allowedValue2"]}`)
|
`e.g. {"type": "string", "maxLength": 15, "enum": ["allowedValue1", "allowedValue2"]}`)
|
||||||
|
set.Flags().BoolVarP(&r.CreateSetter.RecurseSubPackages, "recurse-subpackages", "R", false,
|
||||||
|
"creates setter recursively in all the nested subpackages")
|
||||||
set.Flags().MarkHidden("version")
|
set.Flags().MarkHidden("version")
|
||||||
fixDocs(parent, set)
|
fixDocs(parent, set)
|
||||||
r.Command = set
|
r.Command = set
|
||||||
@@ -111,42 +115,6 @@ func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if setterVersion == "v2" {
|
if setterVersion == "v2" {
|
||||||
var err error
|
|
||||||
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if substitution with same name exists and throw error
|
|
||||||
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + r.CreateSetter.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
subst, _ := openapi.Resolve(&ref)
|
|
||||||
// if substitution already exists with the input setter name, throw error
|
|
||||||
if subst != nil {
|
|
||||||
return errors.Errorf("substitution with name %s already exists, "+
|
|
||||||
"substitution and setter can't have same name", r.CreateSetter.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if setter with same name exists and throw error
|
|
||||||
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + r.CreateSetter.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
setter, _ := openapi.Resolve(&ref)
|
|
||||||
// if setter already exists with the input setter name, throw error
|
|
||||||
if setter != nil {
|
|
||||||
return errors.Errorf("setter with name %s already exists, "+
|
|
||||||
"if you want to modify it, please delete the existing setter and recreate it", r.CreateSetter.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
r.CreateSetter.Description = r.Set.SetPartialField.Description
|
r.CreateSetter.Description = r.Set.SetPartialField.Description
|
||||||
r.CreateSetter.SetBy = r.Set.SetPartialField.SetBy
|
r.CreateSetter.SetBy = r.Set.SetPartialField.SetBy
|
||||||
r.CreateSetter.Type = r.Set.SetPartialField.Type
|
r.CreateSetter.Type = r.Set.SetPartialField.Type
|
||||||
@@ -212,7 +180,60 @@ func (r *CreateSetterRunner) processSchema() error {
|
|||||||
|
|
||||||
func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
|
func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
|
||||||
if setterVersion == "v2" {
|
if setterVersion == "v2" {
|
||||||
return r.CreateSetter.Create(r.OpenAPIFile, args[0])
|
openAPIFileName, err := ext.OpenAPIFileName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.CreateSetter.OpenAPIFileName = openAPIFileName
|
||||||
|
resourcePackagesPaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.CreateSetter.RecurseSubPackages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resourcePackagesPaths) == 0 {
|
||||||
|
return errors.Errorf("unable to find %q in package %q", r.CreateSetter.OpenAPIFileName, args[0])
|
||||||
|
}
|
||||||
|
for _, resourcesPath := range resourcePackagesPaths {
|
||||||
|
r.CreateSetter = settersutil.SetterCreator{
|
||||||
|
Name: r.CreateSetter.Name,
|
||||||
|
SetBy: r.CreateSetter.SetBy,
|
||||||
|
Description: r.CreateSetter.Description,
|
||||||
|
Type: r.CreateSetter.Type,
|
||||||
|
Schema: r.CreateSetter.Schema,
|
||||||
|
FieldName: r.CreateSetter.FieldName,
|
||||||
|
FieldValue: r.CreateSetter.FieldValue,
|
||||||
|
Required: r.CreateSetter.Required,
|
||||||
|
RecurseSubPackages: r.CreateSetter.RecurseSubPackages,
|
||||||
|
OpenAPIFileName: openAPIFileName,
|
||||||
|
OpenAPIPath: filepath.Join(resourcesPath, openAPIFileName),
|
||||||
|
ResourcesPath: resourcesPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add schema present in openAPI file for current package
|
||||||
|
if err := openapi.AddSchemaFromFile(r.CreateSetter.OpenAPIPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.CreateSetter.Create()
|
||||||
|
if err != nil {
|
||||||
|
// return err if there is only package
|
||||||
|
if len(resourcePackagesPaths) == 1 {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// print error message and continue if there are multiple packages to set
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "%s in package %q\n", err.Error(), r.CreateSetter.ResourcesPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "created setter %q in package %q\n", r.CreateSetter.Name, r.CreateSetter.ResourcesPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete schema present in openAPI file for current package
|
||||||
|
if err := openapi.DeleteSchemaInFile(r.CreateSetter.OpenAPIPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rw := &kio.LocalPackageReadWriter{PackagePath: args[0]}
|
rw := &kio.LocalPackageReadWriter{PackagePath: args[0]}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/copyutil"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "replicas" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -81,6 +83,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "replicas" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -122,7 +125,7 @@ openAPI:
|
|||||||
- marker: ${my-tag-setter}
|
- marker: ${my-tag-setter}
|
||||||
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
|
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
|
||||||
`,
|
`,
|
||||||
err: "substitution with name my-image already exists, substitution and setter can't have same name",
|
err: `substitution with name "my-image" already exists, substitution and setter can't have same name`,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -140,7 +143,7 @@ openAPI:
|
|||||||
name: my-image
|
name: my-image
|
||||||
value: "nginx"
|
value: "nginx"
|
||||||
`,
|
`,
|
||||||
err: "setter with name my-image already exists, if you want to modify it, please delete the existing setter and recreate it",
|
err: `setter with name "my-image" already exists, if you want to modify it, please delete the existing setter and recreate it`,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -159,6 +162,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "replicas" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -200,6 +204,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter replicas in package ${baseDir}`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -254,6 +259,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "list" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -354,6 +360,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter replicas in package ${baseDir}`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -400,6 +407,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "replicas" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -437,6 +445,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "foo.bar" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -587,6 +596,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "replicas" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -712,6 +722,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created setter "replicas" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -742,13 +753,14 @@ spec:
|
|||||||
openapi.ResetOpenAPI()
|
openapi.ResetOpenAPI()
|
||||||
defer openapi.ResetOpenAPI()
|
defer openapi.ResetOpenAPI()
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "k8s-cli-")
|
baseDir, err := ioutil.TempDir("", "")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
defer os.Remove(f.Name())
|
defer os.RemoveAll(baseDir)
|
||||||
|
|
||||||
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
|
f := filepath.Join(baseDir, "Krmfile")
|
||||||
|
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -768,13 +780,7 @@ spec:
|
|||||||
test.args = append(test.args, "--schema-path", sch.Name())
|
test.args = append(test.args, "--schema-path", sch.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
old := ext.GetOpenAPIFile
|
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
|
||||||
defer func() { ext.GetOpenAPIFile = old }()
|
|
||||||
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
|
|
||||||
return f.Name(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
|
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -787,7 +793,7 @@ spec:
|
|||||||
runner := commands.NewCreateSetterRunner("")
|
runner := commands.NewCreateSetterRunner("")
|
||||||
out := &bytes.Buffer{}
|
out := &bytes.Buffer{}
|
||||||
runner.Command.SetOut(out)
|
runner.Command.SetOut(out)
|
||||||
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
|
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
|
||||||
err = runner.Command.Execute()
|
err = runner.Command.Execute()
|
||||||
if test.err != "" {
|
if test.err != "" {
|
||||||
if !assert.NotNil(t, err) {
|
if !assert.NotNil(t, err) {
|
||||||
@@ -801,7 +807,14 @@ spec:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !assert.Equal(t, test.out, out.String()) {
|
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
|
||||||
|
expectedNormalized := strings.Replace(expectedOut, "\\", "/", -1)
|
||||||
|
// normalize path format for windows
|
||||||
|
actualNormalized := strings.Replace(
|
||||||
|
strings.Replace(out.String(), "\\", "/", -1),
|
||||||
|
"//", "/", -1)
|
||||||
|
|
||||||
|
if !assert.Equal(t, expectedNormalized, strings.TrimSpace(actualNormalized)) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -815,7 +828,7 @@ spec:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
actualOpenAPI, err := ioutil.ReadFile(f.Name())
|
actualOpenAPI, err := ioutil.ReadFile(f)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -827,3 +840,80 @@ spec:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateSetterSubPackages(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
dataset string
|
||||||
|
packagePath string
|
||||||
|
args []string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "create-setter-recurse-subpackages",
|
||||||
|
dataset: "dataset-without-setters",
|
||||||
|
args: []string{"namespace", "myspace", "-R"},
|
||||||
|
expected: `
|
||||||
|
created setter "namespace" in package "${baseDir}/mysql"
|
||||||
|
created setter "namespace" in package "${baseDir}/mysql/storage"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create-setter-top-level-pkg-no-recurse-subpackages",
|
||||||
|
dataset: "dataset-without-setters",
|
||||||
|
packagePath: "mysql",
|
||||||
|
args: []string{"namespace", "myspace"},
|
||||||
|
expected: `created setter "namespace" in package "${baseDir}/mysql"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create-setter-nested-pkg-no-recurse-subpackages",
|
||||||
|
dataset: "dataset-without-setters",
|
||||||
|
packagePath: "mysql/storage",
|
||||||
|
args: []string{"namespace", "myspace"},
|
||||||
|
expected: `created setter "namespace" in package "${baseDir}/mysql/storage"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create-setter-already-exists",
|
||||||
|
dataset: "dataset-with-setters",
|
||||||
|
packagePath: "mysql",
|
||||||
|
args: []string{"namespace", "myspace", "-R"},
|
||||||
|
expected: `setter with name "namespace" already exists, if you want to modify it, please delete the existing setter and recreate it in package "${baseDir}/mysql"
|
||||||
|
created setter "namespace" in package "${baseDir}/mysql/nosetters"
|
||||||
|
setter with name "namespace" already exists, if you want to modify it, please delete the existing setter and recreate it in package "${baseDir}/mysql/storage"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
// reset the openAPI afterward
|
||||||
|
openapi.ResetOpenAPI()
|
||||||
|
defer openapi.ResetOpenAPI()
|
||||||
|
sourceDir := filepath.Join("test", "testdata", test.dataset)
|
||||||
|
baseDir, err := ioutil.TempDir("", "")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
copyutil.CopyDir(sourceDir, baseDir)
|
||||||
|
defer os.RemoveAll(baseDir)
|
||||||
|
runner := commands.NewCreateSetterRunner("")
|
||||||
|
actual := &bytes.Buffer{}
|
||||||
|
runner.Command.SetOut(actual)
|
||||||
|
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
|
||||||
|
err = runner.Command.Execute()
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize path format for windows
|
||||||
|
actualNormalized := strings.Replace(
|
||||||
|
strings.Replace(actual.String(), "\\", "/", -1),
|
||||||
|
"//", "/", -1)
|
||||||
|
|
||||||
|
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
|
||||||
|
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
|
||||||
|
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/go-openapi/spec"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/pathutil"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
|
|||||||
cs := &cobra.Command{
|
cs := &cobra.Command{
|
||||||
Use: "create-subst DIR NAME",
|
Use: "create-subst DIR NAME",
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
PreRunE: r.preRunE,
|
PreRun: r.preRun,
|
||||||
RunE: r.runE,
|
RunE: r.runE,
|
||||||
}
|
}
|
||||||
cs.Flags().StringVar(&r.CreateSubstitution.FieldName, "field", "",
|
cs.Flags().StringVar(&r.CreateSubstitution.FieldName, "field", "",
|
||||||
@@ -30,6 +30,8 @@ func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
|
|||||||
"value of the field to create substitution for -- e.g. --field-value nginx:0.1.0")
|
"value of the field to create substitution for -- e.g. --field-value nginx:0.1.0")
|
||||||
cs.Flags().StringVar(&r.CreateSubstitution.Pattern, "pattern", "",
|
cs.Flags().StringVar(&r.CreateSubstitution.Pattern, "pattern", "",
|
||||||
`substitution pattern -- e.g. --pattern \${my-image-setter}:\${my-tag-setter}`)
|
`substitution pattern -- e.g. --pattern \${my-image-setter}:\${my-tag-setter}`)
|
||||||
|
cs.Flags().BoolVarP(&r.CreateSubstitution.RecurseSubPackages, "recurse-subpackages", "R", false,
|
||||||
|
"creates substitution recursively in all the nested subpackages")
|
||||||
_ = cs.MarkFlagRequired("pattern")
|
_ = cs.MarkFlagRequired("pattern")
|
||||||
_ = cs.MarkFlagRequired("field-value")
|
_ = cs.MarkFlagRequired("field-value")
|
||||||
fixDocs(parent, cs)
|
fixDocs(parent, cs)
|
||||||
@@ -49,49 +51,58 @@ type CreateSubstitutionRunner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error {
|
func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error {
|
||||||
return handleError(c, r.CreateSubstitution.Create(r.OpenAPIFile, args[0]))
|
openAPIFileName, err := ext.OpenAPIFileName()
|
||||||
}
|
|
||||||
|
|
||||||
func (r *CreateSubstitutionRunner) preRunE(c *cobra.Command, args []string) error {
|
|
||||||
var err error
|
|
||||||
r.CreateSubstitution.Name = args[1]
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
|
r.CreateSubstitution.OpenAPIFileName = openAPIFileName
|
||||||
|
resourcePackagesPaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.CreateSubstitution.RecurseSubPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
|
if len(resourcePackagesPaths) == 0 {
|
||||||
return err
|
return errors.Errorf("unable to find %q in package %q", r.CreateSubstitution.OpenAPIFileName, args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if substitution with same name exists and throw error
|
for _, resourcesPath := range resourcePackagesPaths {
|
||||||
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + r.CreateSubstitution.Name)
|
r.CreateSubstitution = settersutil.SubstitutionCreator{
|
||||||
|
Name: r.CreateSubstitution.Name,
|
||||||
|
FieldName: r.CreateSubstitution.FieldName,
|
||||||
|
FieldValue: r.CreateSubstitution.FieldValue,
|
||||||
|
RecurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
|
||||||
|
Pattern: r.CreateSubstitution.Pattern,
|
||||||
|
OpenAPIFileName: openAPIFileName,
|
||||||
|
OpenAPIPath: filepath.Join(resourcesPath, openAPIFileName),
|
||||||
|
ResourcesPath: resourcesPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add schema present in openAPI file for current package
|
||||||
|
if err := openapi.AddSchemaFromFile(r.CreateSubstitution.OpenAPIPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err := r.CreateSubstitution.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// return err if there is only package
|
||||||
|
if len(resourcePackagesPaths) == 1 {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// print error message and continue if there are multiple packages to set
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "%s in package %q\n", err.Error(), r.CreateSubstitution.ResourcesPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "created substitution %q in package %q\n", r.CreateSubstitution.Name, r.CreateSubstitution.ResourcesPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete schema present in openAPI file for current package
|
||||||
|
if err := openapi.DeleteSchemaInFile(r.CreateSubstitution.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
subst, _ := openapi.Resolve(&ref)
|
|
||||||
// if substitution already exists with the input substitution name, throw error
|
|
||||||
if subst != nil {
|
|
||||||
return errors.Errorf("substitution with name %s already exists", r.CreateSubstitution.Name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if setter with same name exists and throw error
|
|
||||||
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + r.CreateSubstitution.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
setter, _ := openapi.Resolve(&ref)
|
|
||||||
// if setter already exists with input substitution name, throw error
|
|
||||||
if setter != nil {
|
|
||||||
return errors.Errorf(fmt.Sprintf("setter with name %s already exists, "+
|
|
||||||
"substitution and setter can't have same name", r.CreateSubstitution.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *CreateSubstitutionRunner) preRun(c *cobra.Command, args []string) {
|
||||||
|
r.CreateSubstitution.Name = args[1]
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/copyutil"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ openAPI:
|
|||||||
name: my-tag-setter
|
name: my-tag-setter
|
||||||
value: "1.7.9"
|
value: "1.7.9"
|
||||||
`,
|
`,
|
||||||
|
out: `created substitution "my-image-subst" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -123,7 +125,7 @@ openAPI:
|
|||||||
- marker: ${my-tag-setter}
|
- marker: ${my-tag-setter}
|
||||||
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
|
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
|
||||||
`,
|
`,
|
||||||
err: "substitution with name my-image already exists",
|
err: `substitution with name "my-image" already exists`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error if setter with same name exists",
|
name: "error if setter with same name exists",
|
||||||
@@ -140,7 +142,7 @@ openAPI:
|
|||||||
name: my-image
|
name: my-image
|
||||||
value: "nginx"
|
value: "nginx"
|
||||||
`,
|
`,
|
||||||
err: "setter with name my-image already exists, substitution and setter can't have same name",
|
err: `setter with name "my-image" already exists, substitution and setter can't have same name`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "substitution and create setters 1",
|
name: "substitution and create setters 1",
|
||||||
@@ -165,6 +167,7 @@ spec:
|
|||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
`,
|
`,
|
||||||
|
out: `created substitution "my-image-subst" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -253,6 +256,7 @@ openAPI:
|
|||||||
- marker: ${my-tag-setter}
|
- marker: ${my-tag-setter}
|
||||||
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
|
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
|
||||||
`,
|
`,
|
||||||
|
out: `created substitution "my-nested-subst" in package "${baseDir}"`,
|
||||||
expectedOpenAPI: `
|
expectedOpenAPI: `
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: Example
|
kind: Example
|
||||||
@@ -341,7 +345,7 @@ spec:
|
|||||||
substVal: prefix-1234
|
substVal: prefix-1234
|
||||||
|
|
||||||
`,
|
`,
|
||||||
err: "setters must have different name than the substitution: foo",
|
err: `setters must have different name than the substitution: foo`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i := range tests {
|
for i := range tests {
|
||||||
@@ -351,22 +355,18 @@ spec:
|
|||||||
openapi.ResetOpenAPI()
|
openapi.ResetOpenAPI()
|
||||||
defer openapi.ResetOpenAPI()
|
defer openapi.ResetOpenAPI()
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "k8s-cli-")
|
baseDir, err := ioutil.TempDir("", "")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
defer os.Remove(f.Name())
|
defer os.RemoveAll(baseDir)
|
||||||
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
|
f := filepath.Join(baseDir, "Krmfile")
|
||||||
|
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
old := ext.GetOpenAPIFile
|
|
||||||
defer func() { ext.GetOpenAPIFile = old }()
|
|
||||||
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
|
|
||||||
return f.Name(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
|
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -379,7 +379,7 @@ spec:
|
|||||||
runner := commands.NewCreateSubstitutionRunner("")
|
runner := commands.NewCreateSubstitutionRunner("")
|
||||||
out := &bytes.Buffer{}
|
out := &bytes.Buffer{}
|
||||||
runner.Command.SetOut(out)
|
runner.Command.SetOut(out)
|
||||||
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
|
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
|
||||||
err = runner.Command.Execute()
|
err = runner.Command.Execute()
|
||||||
|
|
||||||
if test.err != "" {
|
if test.err != "" {
|
||||||
@@ -393,7 +393,14 @@ spec:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !assert.Equal(t, test.out, out.String()) {
|
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
|
||||||
|
expectedNormalized := strings.Replace(expectedOut, "\\", "/", -1)
|
||||||
|
// normalize path format for windows
|
||||||
|
actualNormalized := strings.Replace(
|
||||||
|
strings.Replace(out.String(), "\\", "/", -1),
|
||||||
|
"//", "/", -1)
|
||||||
|
|
||||||
|
if !assert.Equal(t, expectedNormalized, strings.TrimSpace(actualNormalized)) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +414,7 @@ spec:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
actualOpenAPI, err := ioutil.ReadFile(f.Name())
|
actualOpenAPI, err := ioutil.ReadFile(f)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -419,3 +426,80 @@ spec:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateSubstSubPackages(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
dataset string
|
||||||
|
packagePath string
|
||||||
|
args []string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "create-subst-recurse-subpackages",
|
||||||
|
dataset: "dataset-without-setters",
|
||||||
|
args: []string{"image-tag", "--field-value", "mysql:1.7.9", "--pattern", "${image}:${tag}", "-R"},
|
||||||
|
expected: `
|
||||||
|
created substitution "image-tag" in package "${baseDir}/mysql"
|
||||||
|
created substitution "image-tag" in package "${baseDir}/mysql/storage"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create-subst-top-level-pkg-no-recurse-subpackages",
|
||||||
|
dataset: "dataset-without-setters",
|
||||||
|
packagePath: "mysql",
|
||||||
|
args: []string{"image-tag", "--field-value", "mysql:1.7.9", "--pattern", "${image}:${tag}"},
|
||||||
|
expected: `created substitution "image-tag" in package "${baseDir}/mysql"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create-subst-nested-pkg-no-recurse-subpackages",
|
||||||
|
dataset: "dataset-without-setters",
|
||||||
|
packagePath: "mysql/storage",
|
||||||
|
args: []string{"image-tag", "--field-value", "storage:1.7.9", "--pattern", "${image}:${tag}"},
|
||||||
|
expected: `created substitution "image-tag" in package "${baseDir}/mysql/storage"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create-subst-already-exists",
|
||||||
|
dataset: "dataset-with-setters",
|
||||||
|
packagePath: "mysql",
|
||||||
|
args: []string{"image-tag", "--field-value", "mysql:1.7.9", "--pattern", "${image}:${tag}", "-R"},
|
||||||
|
expected: `substitution with name "image-tag" already exists in package "${baseDir}/mysql"
|
||||||
|
created substitution "image-tag" in package "${baseDir}/mysql/nosetters"
|
||||||
|
created substitution "image-tag" in package "${baseDir}/mysql/storage"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
// reset the openAPI afterward
|
||||||
|
openapi.ResetOpenAPI()
|
||||||
|
defer openapi.ResetOpenAPI()
|
||||||
|
sourceDir := filepath.Join("test", "testdata", test.dataset)
|
||||||
|
baseDir, err := ioutil.TempDir("", "")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
copyutil.CopyDir(sourceDir, baseDir)
|
||||||
|
defer os.RemoveAll(baseDir)
|
||||||
|
runner := commands.NewCreateSubstitutionRunner("")
|
||||||
|
actual := &bytes.Buffer{}
|
||||||
|
runner.Command.SetOut(actual)
|
||||||
|
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
|
||||||
|
err = runner.Command.Execute()
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize path format for windows
|
||||||
|
actualNormalized := strings.Replace(
|
||||||
|
strings.Replace(actual.String(), "\\", "/", -1),
|
||||||
|
"//", "/", -1)
|
||||||
|
|
||||||
|
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
|
||||||
|
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
|
||||||
|
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
@@ -70,21 +71,21 @@ func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
openAPIPaths, err := pathutil.SubDirsWithFile(args[0], openAPIFileName)
|
resourcePaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(openAPIPaths) == 0 {
|
if len(resourcePaths) == 0 {
|
||||||
return errors.Errorf("unable to find %s in %s", openAPIFileName, args[0])
|
return errors.Errorf("unable to find %s in package %s", openAPIFileName, args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// list setters for all the subpackages with openAPI file paths
|
// list setters for all the subpackages with openAPI file paths
|
||||||
for _, openAPIPath := range openAPIPaths {
|
for _, resourcePath := range resourcePaths {
|
||||||
r.List = setters2.List{
|
r.List = setters2.List{
|
||||||
Name: r.List.Name,
|
Name: r.List.Name,
|
||||||
OpenAPIFileName: openAPIFileName,
|
OpenAPIFileName: openAPIFileName,
|
||||||
}
|
}
|
||||||
resourcePath := strings.TrimSuffix(openAPIPath, openAPIFileName)
|
openAPIPath := filepath.Join(resourcePath, openAPIFileName)
|
||||||
fmt.Fprintf(c.OutOrStdout(), "%s\n", resourcePath)
|
fmt.Fprintf(c.OutOrStdout(), "%s\n", resourcePath)
|
||||||
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
|
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -471,9 +471,10 @@ func TestListSettersSubPackages(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "list-replicas",
|
name: "list-replicas",
|
||||||
dataset: "dataset1",
|
dataset: "dataset-with-setters",
|
||||||
args: []string{"--include-subst"},
|
args: []string{"--include-subst"},
|
||||||
expected: `test/testdata/dataset1/mysql/
|
expected: `
|
||||||
|
test/testdata/dataset-with-setters/mysql
|
||||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||||
image mysql 1 No
|
image mysql 1 No
|
||||||
namespace myspace 1 No
|
namespace myspace 1 No
|
||||||
@@ -481,9 +482,9 @@ func TestListSettersSubPackages(t *testing.T) {
|
|||||||
--------------- ----------------- --------------
|
--------------- ----------------- --------------
|
||||||
SUBSTITUTION PATTERN REFERENCES
|
SUBSTITUTION PATTERN REFERENCES
|
||||||
image-tag ${image}:${tag} [image,tag]
|
image-tag ${image}:${tag} [image,tag]
|
||||||
test/testdata/dataset1/mysql/nosetters/
|
test/testdata/dataset-with-setters/mysql/nosetters
|
||||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||||
test/testdata/dataset1/mysql/storage/
|
test/testdata/dataset-with-setters/mysql/storage
|
||||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||||
namespace myspace 1 No
|
namespace myspace 1 No
|
||||||
`,
|
`,
|
||||||
@@ -509,7 +510,7 @@ test/testdata/dataset1/mysql/storage/
|
|||||||
// normalize path format for windows
|
// normalize path format for windows
|
||||||
actualNormalized := strings.Replace(actual.String(), "\\", "/", -1)
|
actualNormalized := strings.Replace(actual.String(), "\\", "/", -1)
|
||||||
|
|
||||||
if !assert.Equal(t, test.expected, actualNormalized) {
|
if !assert.Equal(t, strings.TrimSpace(test.expected), strings.TrimSpace(actualNormalized)) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -13,6 +14,7 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/pathutil"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||||
)
|
)
|
||||||
@@ -39,6 +41,8 @@ func NewSetRunner(parent string) *SetRunner {
|
|||||||
"annotate the field with a description of its value")
|
"annotate the field with a description of its value")
|
||||||
c.Flags().StringVar(&setterVersion, "version", "",
|
c.Flags().StringVar(&setterVersion, "version", "",
|
||||||
"use this version of the setter format")
|
"use this version of the setter format")
|
||||||
|
c.Flags().BoolVarP(&r.Set.RecurseSubPackages, "recurse-subpackages", "R", false,
|
||||||
|
"sets recursively in all the nested subpackages")
|
||||||
c.Flags().MarkHidden("version")
|
c.Flags().MarkHidden("version")
|
||||||
|
|
||||||
return r
|
return r
|
||||||
@@ -126,15 +130,53 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
|
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
|
||||||
if setterVersion == "v2" {
|
if setterVersion == "v2" {
|
||||||
count, err := r.Set.Set(r.OpenAPIFile, args[0])
|
openAPIFileName, err := ext.OpenAPIFileName()
|
||||||
fmt.Fprintf(c.OutOrStdout(), "set %d fields\n", count)
|
if err != nil {
|
||||||
return handleError(c, err)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Set.OpenAPIFileName = openAPIFileName
|
||||||
|
resourcePackagesPaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.Set.RecurseSubPackages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resourcePackagesPaths) == 0 {
|
||||||
|
return errors.Errorf("unable to find %q in package %q", r.Set.OpenAPIFileName, args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, resourcesPath := range resourcePackagesPaths {
|
||||||
|
r.Set = settersutil.FieldSetter{
|
||||||
|
Name: r.Set.Name,
|
||||||
|
Value: r.Set.Value,
|
||||||
|
ListValues: r.Set.ListValues,
|
||||||
|
Description: r.Set.Description,
|
||||||
|
SetBy: r.Set.SetBy,
|
||||||
|
Count: 0,
|
||||||
|
OpenAPIPath: filepath.Join(resourcesPath, openAPIFileName),
|
||||||
|
OpenAPIFileName: openAPIFileName,
|
||||||
|
ResourcesPath: resourcesPath,
|
||||||
|
RecurseSubPackages: r.Set.RecurseSubPackages,
|
||||||
|
}
|
||||||
|
count, err := r.Set.Set()
|
||||||
|
if err != nil {
|
||||||
|
// return err if there is only package
|
||||||
|
if len(resourcePackagesPaths) == 1 {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// print error message and continue if there are multiple packages to set
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "%s in package %q\n", err.Error(), r.Set.ResourcesPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(c.OutOrStdout(), "set %d fields in package %q\n", count, r.Set.ResourcesPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if len(args) > 2 || c.Flag("values").Changed {
|
if len(args) > 2 || c.Flag("values").Changed {
|
||||||
return handleError(c, r.perform(c, args))
|
return handleError(c, r.perform(c, args))
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/copyutil"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1013,22 +1014,19 @@ spec:
|
|||||||
openapi.ResetOpenAPI()
|
openapi.ResetOpenAPI()
|
||||||
defer openapi.ResetOpenAPI()
|
defer openapi.ResetOpenAPI()
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "k8s-cli-")
|
baseDir, err := ioutil.TempDir("", "")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
defer os.Remove(f.Name())
|
defer os.RemoveAll(baseDir)
|
||||||
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
|
|
||||||
|
f := filepath.Join(baseDir, "Krmfile")
|
||||||
|
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
old := ext.GetOpenAPIFile
|
|
||||||
defer func() { ext.GetOpenAPIFile = old }()
|
|
||||||
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
|
|
||||||
return f.Name(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
|
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1039,7 @@ spec:
|
|||||||
runner := commands.NewSetRunner("")
|
runner := commands.NewSetRunner("")
|
||||||
out := &bytes.Buffer{}
|
out := &bytes.Buffer{}
|
||||||
runner.Command.SetOut(out)
|
runner.Command.SetOut(out)
|
||||||
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
|
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
|
||||||
err = runner.Command.Execute()
|
err = runner.Command.Execute()
|
||||||
if test.errMsg != "" {
|
if test.errMsg != "" {
|
||||||
if !assert.NotNil(t, err) {
|
if !assert.NotNil(t, err) {
|
||||||
@@ -1056,7 +1054,7 @@ spec:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.errMsg == "" && !assert.Equal(t, test.out, out.String()) {
|
if test.errMsg == "" && !assert.Contains(t, out.String(), strings.TrimSpace(test.out)) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1070,7 +1068,7 @@ spec:
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
actualOpenAPI, err := ioutil.ReadFile(f.Name())
|
actualOpenAPI, err := ioutil.ReadFile(f)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -1082,3 +1080,78 @@ spec:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetSubPackages(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
dataset string
|
||||||
|
packagePath string
|
||||||
|
args []string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "set-recurse-subpackages",
|
||||||
|
dataset: "dataset-with-setters",
|
||||||
|
args: []string{"namespace", "otherspace", "-R"},
|
||||||
|
expected: `
|
||||||
|
set 1 fields in package "${baseDir}/mysql"
|
||||||
|
setter "namespace" is not found in package "${baseDir}/mysql/nosetters"
|
||||||
|
set 1 fields in package "${baseDir}/mysql/storage"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set-top-level-pkg-no-recurse-subpackages",
|
||||||
|
dataset: "dataset-with-setters",
|
||||||
|
packagePath: "mysql",
|
||||||
|
args: []string{"namespace", "otherspace"},
|
||||||
|
expected: `
|
||||||
|
set 1 fields in package "${baseDir}/mysql"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set-nested-pkg-no-recurse-subpackages",
|
||||||
|
dataset: "dataset-with-setters",
|
||||||
|
packagePath: "mysql/storage",
|
||||||
|
args: []string{"namespace", "otherspace"},
|
||||||
|
expected: `
|
||||||
|
set 1 fields in package "${baseDir}/mysql/storage"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
// reset the openAPI afterward
|
||||||
|
openapi.ResetOpenAPI()
|
||||||
|
defer openapi.ResetOpenAPI()
|
||||||
|
sourceDir := filepath.Join("test", "testdata", test.dataset)
|
||||||
|
baseDir, err := ioutil.TempDir("", "")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
copyutil.CopyDir(sourceDir, baseDir)
|
||||||
|
defer os.RemoveAll(baseDir)
|
||||||
|
runner := commands.NewSetRunner("")
|
||||||
|
actual := &bytes.Buffer{}
|
||||||
|
runner.Command.SetOut(actual)
|
||||||
|
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
|
||||||
|
err = runner.Command.Execute()
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize path format for windows
|
||||||
|
actualNormalized := strings.Replace(
|
||||||
|
strings.Replace(actual.String(), "\\", "/", -1),
|
||||||
|
"//", "/", -1)
|
||||||
|
|
||||||
|
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
|
||||||
|
expectedNormalized := strings.Replace(
|
||||||
|
strings.Replace(expected, "\\", "/", -1),
|
||||||
|
"//", "/", -1)
|
||||||
|
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ items:
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: mysql-deployment
|
name: mysql-deployment
|
||||||
namespace: myspace # {"$openapi":"namespace"}
|
namespace: myspace
|
||||||
annotations:
|
annotations:
|
||||||
config.kubernetes.io/index: '0'
|
config.kubernetes.io/index: '0'
|
||||||
config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
|
config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
|
||||||
@@ -192,7 +192,7 @@ items:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: mysql
|
- name: mysql
|
||||||
image: mysql:1.7.9 # {"$openapi":"image-tag"}
|
image: mysql:1.7.9
|
||||||
- apiVersion: apps/v1
|
- apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
@@ -212,7 +212,7 @@ items:
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: storage-deployment
|
name: storage-deployment
|
||||||
namespace: myspace # {"$openapi":"namespace"}
|
namespace: myspace
|
||||||
annotations:
|
annotations:
|
||||||
config.kubernetes.io/index: '0'
|
config.kubernetes.io/index: '0'
|
||||||
config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'
|
config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ openAPI:
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
expectedStdOut: `
|
expectedStdOut: `
|
||||||
./
|
.
|
||||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||||
replicas 3 1 No
|
replicas 3 1 No
|
||||||
`,
|
`,
|
||||||
|
|||||||
6
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/Krmfile
vendored
Normal file
6
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/Krmfile
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: krm.dev/v1alpha1
|
||||||
|
kind: Krmfile
|
||||||
|
metadata:
|
||||||
|
name: mysql
|
||||||
|
packageMetadata:
|
||||||
|
shortDescription: sample description
|
||||||
15
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/deployment.yaml
vendored
Normal file
15
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/deployment.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
namespace: myspace
|
||||||
|
name: mysql-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: mysql
|
||||||
|
image: mysql:1.7.9
|
||||||
6
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/storage/Krmfile
vendored
Normal file
6
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/storage/Krmfile
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: krm.dev/v1alpha1
|
||||||
|
kind: Krmfile
|
||||||
|
metadata:
|
||||||
|
name: storage
|
||||||
|
packageMetadata:
|
||||||
|
shortDescription: sample description
|
||||||
15
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/storage/deployment.yaml
vendored
Normal file
15
cmd/config/internal/commands/test/testdata/dataset-without-setters/mysql/storage/deployment.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2019 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
namespace: myspace
|
||||||
|
name: storage-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 4
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: storage
|
||||||
|
image: storage:1.7.7
|
||||||
@@ -22,3 +22,5 @@ exclude (
|
|||||||
replace sigs.k8s.io/kustomize/api v0.6.0 => ../api
|
replace sigs.k8s.io/kustomize/api v0.6.0 => ../api
|
||||||
|
|
||||||
replace sigs.k8s.io/kustomize/cmd/config v0.6.0 => ../cmd/config
|
replace sigs.k8s.io/kustomize/cmd/config v0.6.0 => ../cmd/config
|
||||||
|
|
||||||
|
replace sigs.k8s.io/kustomize/kyaml v0.7.1 => ../kyaml
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||||
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
@@ -743,12 +745,17 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
|||||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
||||||
|
sigs.k8s.io/cli-utils v0.18.0 h1:PPFUhhwKsdMiYYm1DY9lZursNWSAEj8FYgMCZKVvOkQ=
|
||||||
|
sigs.k8s.io/cli-utils v0.18.0/go.mod h1:B7KdqkSkHNIUn3cFbaR4aKUZMKtr+Benboi1w/HW/Fg=
|
||||||
sigs.k8s.io/cli-utils v0.19.2 h1:BwidWPZ3Qop4RBOl27MU8uN/BSEZPQ8rw1mwsNofXfw=
|
sigs.k8s.io/cli-utils v0.19.2 h1:BwidWPZ3Qop4RBOl27MU8uN/BSEZPQ8rw1mwsNofXfw=
|
||||||
sigs.k8s.io/cli-utils v0.19.2/go.mod h1:ulIQPERYwkYksNriRknJRbGECDR/ZZROpkiThlXBtB4=
|
sigs.k8s.io/cli-utils v0.19.2/go.mod h1:ulIQPERYwkYksNriRknJRbGECDR/ZZROpkiThlXBtB4=
|
||||||
sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg=
|
sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg=
|
||||||
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
|
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
||||||
|
sigs.k8s.io/kustomize/cmd/config v0.6.0 h1:03tjs3SjvsumZjabctLicNUQwYlAeUqmRk1H4JBK+wI=
|
||||||
|
sigs.k8s.io/kustomize/cmd/config v0.6.0/go.mod h1:azYDRZ/lprMhKqF4DbquWS0cfBFaInLM3LN+zuAXRDI=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.6.0/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
|
sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=
|
sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=
|
||||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/kyaml/ext"
|
"sigs.k8s.io/kustomize/kyaml/ext"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ignoreFilesMatcher handles `.krmignore` files, which allows for ignoring
|
// IgnoreFilesMatcher handles `.krmignore` files, which allows for ignoring
|
||||||
// files or folders in a package. The format of this file is a subset of the
|
// files or folders in a package. The format of this file is a subset of the
|
||||||
// gitignore format, with recursive patterns (like a/**/c) not supported. If a
|
// gitignore format, with recursive patterns (like a/**/c) not supported. If a
|
||||||
// file or folder matches any of the patterns in the .krmignore file for the
|
// file or folder matches any of the patterns in the .krmignore file for the
|
||||||
@@ -30,14 +30,14 @@ import (
|
|||||||
// package contains a pattern that ignores the directory foo, if foo is a
|
// package contains a pattern that ignores the directory foo, if foo is a
|
||||||
// subpackage, it will still be included if the IncludeSubpackages property
|
// subpackage, it will still be included if the IncludeSubpackages property
|
||||||
// is set to true
|
// is set to true
|
||||||
type ignoreFilesMatcher struct {
|
type IgnoreFilesMatcher struct {
|
||||||
matchers []matcher
|
matchers []matcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// readIgnoreFile checks whether there is a .krmignore file in the path, and
|
// readIgnoreFile checks whether there is a .krmignore file in the path, and
|
||||||
// if it is, reads it in and turns it into a matcher. If we can't find a file,
|
// if it is, reads it in and turns it into a matcher. If we can't find a file,
|
||||||
// we just add a matcher that match nothing.
|
// we just add a matcher that match nothing.
|
||||||
func (i *ignoreFilesMatcher) readIgnoreFile(path string) error {
|
func (i *IgnoreFilesMatcher) readIgnoreFile(path string) error {
|
||||||
m, err := gitignore.NewGitIgnore(filepath.Join(path, ext.GetIgnoreFileName()))
|
m, err := gitignore.NewGitIgnore(filepath.Join(path, ext.GetIgnoreFileName()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@@ -60,7 +60,7 @@ func (i *ignoreFilesMatcher) readIgnoreFile(path string) error {
|
|||||||
// is correct for the provided filepath. Matchers are removed once
|
// is correct for the provided filepath. Matchers are removed once
|
||||||
// we encounter a filepath that is not a subpath of the basepath for
|
// we encounter a filepath that is not a subpath of the basepath for
|
||||||
// the matcher.
|
// the matcher.
|
||||||
func (i *ignoreFilesMatcher) verifyPath(path string) {
|
func (i *IgnoreFilesMatcher) verifyPath(path string) {
|
||||||
for j := len(i.matchers) - 1; j >= 0; j-- {
|
for j := len(i.matchers) - 1; j >= 0; j-- {
|
||||||
matcher := i.matchers[j]
|
matcher := i.matchers[j]
|
||||||
if !strings.HasPrefix(path, matcher.basePath) {
|
if !strings.HasPrefix(path, matcher.basePath) {
|
||||||
@@ -72,7 +72,7 @@ func (i *ignoreFilesMatcher) verifyPath(path string) {
|
|||||||
|
|
||||||
// matchFile checks whether the file given by the provided path matches
|
// matchFile checks whether the file given by the provided path matches
|
||||||
// any of the patterns in the .krmignore file for the package.
|
// any of the patterns in the .krmignore file for the package.
|
||||||
func (i *ignoreFilesMatcher) matchFile(path string) bool {
|
func (i *IgnoreFilesMatcher) matchFile(path string) bool {
|
||||||
if len(i.matchers) == 0 {
|
if len(i.matchers) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ func (i *ignoreFilesMatcher) matchFile(path string) bool {
|
|||||||
|
|
||||||
// matchFile checks whether the directory given by the provided path matches
|
// matchFile checks whether the directory given by the provided path matches
|
||||||
// any of the patterns in the .krmignore file for the package.
|
// any of the patterns in the .krmignore file for the package.
|
||||||
func (i *ignoreFilesMatcher) matchDir(path string) bool {
|
func (i *IgnoreFilesMatcher) matchDir(path string) bool {
|
||||||
if len(i.matchers) == 0 {
|
if len(i.matchers) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ testfile.yaml
|
|||||||
assert.FailNow(t, err.Error())
|
assert.FailNow(t, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
ignoreFilesMatcher := ignoreFilesMatcher{}
|
ignoreFilesMatcher := IgnoreFilesMatcher{}
|
||||||
err = ignoreFilesMatcher.readIgnoreFile(dir)
|
err = ignoreFilesMatcher.readIgnoreFile(dir)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ func (r *LocalPackageReadWriter) Read() ([]*yaml.RNode, error) {
|
|||||||
IncludeSubpackages: r.IncludeSubpackages,
|
IncludeSubpackages: r.IncludeSubpackages,
|
||||||
ErrorIfNonResources: r.ErrorIfNonResources,
|
ErrorIfNonResources: r.ErrorIfNonResources,
|
||||||
SetAnnotations: r.SetAnnotations,
|
SetAnnotations: r.SetAnnotations,
|
||||||
|
PackageFileName: r.PackageFileName,
|
||||||
}.Read()
|
}.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err)
|
return nil, errors.Wrap(err)
|
||||||
@@ -185,7 +186,7 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) {
|
|||||||
var operand ResourceNodeSlice
|
var operand ResourceNodeSlice
|
||||||
var pathRelativeTo string
|
var pathRelativeTo string
|
||||||
var err error
|
var err error
|
||||||
ignoreFilesMatcher := &ignoreFilesMatcher{}
|
ignoreFilesMatcher := &IgnoreFilesMatcher{}
|
||||||
r.PackagePath, err = filepath.Abs(r.PackagePath)
|
r.PackagePath, err = filepath.Abs(r.PackagePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err)
|
return nil, errors.Wrap(err)
|
||||||
@@ -257,7 +258,7 @@ func (r *LocalPackageReader) readFile(path string, _ os.FileInfo) ([]*yaml.RNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ShouldSkipFile returns true if the file should be skipped
|
// ShouldSkipFile returns true if the file should be skipped
|
||||||
func (r *LocalPackageReader) ShouldSkipFile(path string, matcher *ignoreFilesMatcher) (bool, error) {
|
func (r *LocalPackageReader) ShouldSkipFile(path string, matcher *IgnoreFilesMatcher) (bool, error) {
|
||||||
// check if the file is covered by a .krmignore file.
|
// check if the file is covered by a .krmignore file.
|
||||||
if matcher.matchFile(path) {
|
if matcher.matchFile(path) {
|
||||||
return false, nil
|
return false, nil
|
||||||
@@ -285,7 +286,7 @@ func (r *LocalPackageReader) initReaderAnnotations(path string, _ os.FileInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ShouldSkipDir returns a filepath.SkipDir if the directory should be skipped
|
// ShouldSkipDir returns a filepath.SkipDir if the directory should be skipped
|
||||||
func (r *LocalPackageReader) ShouldSkipDir(path string, matcher *ignoreFilesMatcher) error {
|
func (r *LocalPackageReader) ShouldSkipDir(path string, matcher *IgnoreFilesMatcher) error {
|
||||||
if r.PackageFileName == "" {
|
if r.PackageFileName == "" {
|
||||||
// If the folder is not a package, but covered by the .krmignore file,
|
// If the folder is not a package, but covered by the .krmignore file,
|
||||||
// we skip it.
|
// we skip it.
|
||||||
|
|||||||
@@ -66,6 +66,41 @@ func AddSchemaFromFile(path string) error {
|
|||||||
return AddSchemaFromFileUsingField(path, SupplementaryOpenAPIFieldName)
|
return AddSchemaFromFileUsingField(path, SupplementaryOpenAPIFieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSchemaInFile reads the file at path and removes all the openAPI definitions
|
||||||
|
// present in file from global schema
|
||||||
|
func DeleteSchemaInFile(path string) error {
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
object, err := yaml.Parse(string(b))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
definitions, err := object.Pipe(yaml.Lookup(SupplementaryOpenAPIFieldName, "definitions"))
|
||||||
|
if definitions == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields, err := definitions.Fields()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
_, ok := globalSchema.schema.Definitions[field]
|
||||||
|
if ok {
|
||||||
|
delete(globalSchema.schema.Definitions, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddSchemaFromFileUsingField reads the file at path and parses the OpenAPI definitions
|
// AddSchemaFromFileUsingField reads the file at path and parses the OpenAPI definitions
|
||||||
// from the specified field. If field is the empty string, use the whole document as
|
// from the specified field. If field is the empty string, use the whole document as
|
||||||
// OpenAPI.
|
// OpenAPI.
|
||||||
|
|||||||
@@ -160,6 +160,82 @@ openAPI:
|
|||||||
fmt.Sprintf("%v", s.Schema.Extensions))
|
fmt.Sprintf("%v", s.Schema.Extensions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteSchemaInFile(t *testing.T) {
|
||||||
|
ResetOpenAPI()
|
||||||
|
inputyaml := `
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
io.k8s.cli.setters.image-name:
|
||||||
|
x-k8s-cli:
|
||||||
|
setter:
|
||||||
|
name: image-name
|
||||||
|
value: "nginx"
|
||||||
|
`
|
||||||
|
f, err := ioutil.TempFile("", "openapi-")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = AddSchemaFromFile(f.Name())
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
|
||||||
|
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
assert.Equal(t, `map[x-k8s-cli:map[setter:map[name:image-name value:nginx]]]`,
|
||||||
|
fmt.Sprintf("%v", s.Schema.Extensions))
|
||||||
|
|
||||||
|
err = DeleteSchemaInFile(f.Name())
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
|
||||||
|
|
||||||
|
if !assert.Error(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.Equal(t, `object has no key "io.k8s.cli.setters.image-name"`, err.Error()) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteSchemaInFileNoDefs(t *testing.T) {
|
||||||
|
ResetOpenAPI()
|
||||||
|
inputyaml := `
|
||||||
|
openAPI:
|
||||||
|
definitions:
|
||||||
|
`
|
||||||
|
f, err := ioutil.TempFile("", "openapi-")
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = AddSchemaFromFile(f.Name())
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DeleteSchemaInFile(f.Name())
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPopulateDefsInOpenAPI_Substitution(t *testing.T) {
|
func TestPopulateDefsInOpenAPI_Substitution(t *testing.T) {
|
||||||
ResetOpenAPI()
|
ResetOpenAPI()
|
||||||
inputyaml := `
|
inputyaml := `
|
||||||
|
|||||||
@@ -6,23 +6,29 @@ package pathutil
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SubDirsWithFile takes the root directory path and returns all the paths of
|
// DirsWithFile takes the root directory path and returns all the paths of
|
||||||
// sub-directories which contain file with input fileName including itself
|
// sub-directories(including itself) which contain file with input fileName
|
||||||
func SubDirsWithFile(root, fileName string) ([]string, error) {
|
// at top level if recurse is true
|
||||||
|
func DirsWithFile(root, fileName string, recurse bool) ([]string, error) {
|
||||||
var res []string
|
var res []string
|
||||||
|
if !recurse {
|
||||||
|
// check if the file with fileName is present in root and return it
|
||||||
|
// else return empty list
|
||||||
|
_, err := os.Stat(filepath.Join(root, fileName))
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
res = append(res, root)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
err := filepath.Walk(root,
|
err := filepath.Walk(root,
|
||||||
func(path string, info os.FileInfo, err error) error {
|
func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(path, fileName) {
|
if filepath.Base(path) == fileName {
|
||||||
if root == "." {
|
res = append(res, filepath.Dir(path))
|
||||||
path = root + "/" + path
|
|
||||||
}
|
|
||||||
res = append(res, path)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,6 +13,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSubDirsWithFile(t *testing.T) {
|
func TestSubDirsWithFile(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
fileName string
|
||||||
|
recurse bool
|
||||||
|
outFilesCount int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "dirs-with-file-recurse",
|
||||||
|
fileName: "Krmfile",
|
||||||
|
outFilesCount: 3,
|
||||||
|
recurse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dirs-with-non-existent-file-recurse",
|
||||||
|
fileName: "non-existent-file.txt",
|
||||||
|
outFilesCount: 0,
|
||||||
|
recurse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dir-with-file-no-recurse",
|
||||||
|
fileName: "Krmfile",
|
||||||
|
outFilesCount: 1,
|
||||||
|
recurse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "")
|
dir, err := ioutil.TempDir("", "")
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
@@ -23,28 +49,17 @@ func TestSubDirsWithFile(t *testing.T) {
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := SubDirsWithFile(dir, "Krmfile")
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
res, err := DirsWithFile(dir, test.fileName, test.recurse)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if !assert.Equal(t, 3, len(res)) {
|
if !assert.Equal(t, test.outFilesCount, len(res)) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
func TestSubDirsWithFileNoMatch(t *testing.T) {
|
|
||||||
dir, err := ioutil.TempDir("", "")
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
res, err := SubDirsWithFile(dir, "non-existent-file.txt")
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
var expected []string
|
|
||||||
if !assert.Equal(t, expected, res) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -367,14 +367,14 @@ func (s SetOpenAPI) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if oa == nil {
|
if oa == nil {
|
||||||
return nil, errors.Errorf("no setter %s found", s.Name)
|
return nil, errors.Errorf("setter %q is not found", s.Name)
|
||||||
}
|
}
|
||||||
def, err := oa.Pipe(yaml.Lookup("x-k8s-cli", "setter"))
|
def, err := oa.Pipe(yaml.Lookup("x-k8s-cli", "setter"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if def == nil {
|
if def == nil {
|
||||||
return nil, errors.Errorf("no setter %s found", s.Name)
|
return nil, errors.Errorf("setter %q is not found", s.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// record the OpenAPI type for the setter
|
// record the OpenAPI type for the setter
|
||||||
|
|||||||
@@ -1271,7 +1271,7 @@ openAPI:
|
|||||||
{
|
{
|
||||||
name: "error",
|
name: "error",
|
||||||
setter: "replicas",
|
setter: "replicas",
|
||||||
err: "no setter replicas found",
|
err: `setter "replicas" is not found`,
|
||||||
input: `
|
input: `
|
||||||
openAPI:
|
openAPI:
|
||||||
definitions:
|
definitions:
|
||||||
|
|||||||
@@ -32,16 +32,20 @@ type FieldSetter struct {
|
|||||||
|
|
||||||
OpenAPIPath string
|
OpenAPIPath string
|
||||||
|
|
||||||
|
OpenAPIFileName string
|
||||||
|
|
||||||
ResourcesPath string
|
ResourcesPath string
|
||||||
|
|
||||||
|
RecurseSubPackages bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FieldSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (fs *FieldSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
fs.Count, _ = fs.Set(fs.OpenAPIPath, fs.ResourcesPath)
|
fs.Count, _ = fs.Set()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set updates the OpenAPI definitions and resources with the new setter value
|
// Set updates the OpenAPI definitions and resources with the new setter value
|
||||||
func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
|
func (fs FieldSetter) Set() (int, error) {
|
||||||
// Update the OpenAPI definitions
|
// Update the OpenAPI definitions
|
||||||
soa := setters2.SetOpenAPI{
|
soa := setters2.SetOpenAPI{
|
||||||
Name: fs.Name,
|
Name: fs.Name,
|
||||||
@@ -55,30 +59,30 @@ func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
|
|||||||
// at to get the value and set it to resource files, but if there is error
|
// at to get the value and set it to resource files, but if there is error
|
||||||
// after updating openAPI file and while updating resources, the openAPI
|
// after updating openAPI file and while updating resources, the openAPI
|
||||||
// file should be reverted, as set operation failed
|
// file should be reverted, as set operation failed
|
||||||
stat, err := os.Stat(openAPIPath)
|
stat, err := os.Stat(fs.OpenAPIPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
curOpenAPI, err := ioutil.ReadFile(openAPIPath)
|
curOpenAPI, err := ioutil.ReadFile(fs.OpenAPIPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the new input value to openAPI file
|
// write the new input value to openAPI file
|
||||||
if err := soa.UpdateFile(openAPIPath); err != nil {
|
if err := soa.UpdateFile(fs.OpenAPIPath); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the updated definitions
|
// Load the updated definitions
|
||||||
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
if err := openapi.AddSchemaFromFile(fs.OpenAPIPath); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the resources with the new value
|
// Update the resources with the new value
|
||||||
// Set NoDeleteFiles to true as SetAll will return only the nodes of files which should be updated and
|
// Set NoDeleteFiles to true as SetAll will return only the nodes of files which should be updated and
|
||||||
// hence, rest of the files should not be deleted
|
// hence, rest of the files should not be deleted
|
||||||
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath, NoDeleteFiles: true}
|
inout := &kio.LocalPackageReadWriter{PackagePath: fs.ResourcesPath, NoDeleteFiles: true, PackageFileName: fs.OpenAPIFileName}
|
||||||
s := &setters2.Set{Name: fs.Name}
|
s := &setters2.Set{Name: fs.Name}
|
||||||
err = kio.Pipeline{
|
err = kio.Pipeline{
|
||||||
Inputs: []kio.Reader{inout},
|
Inputs: []kio.Reader{inout},
|
||||||
@@ -88,7 +92,7 @@ func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
|
|||||||
|
|
||||||
// revert openAPI file if set operation fails
|
// revert openAPI file if set operation fails
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if writeErr := ioutil.WriteFile(openAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
|
if writeErr := ioutil.WriteFile(fs.OpenAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
|
||||||
return 0, writeErr
|
return 0, writeErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ type SetterCreator struct {
|
|||||||
// the package publisher's intent to make the setter required to be set.
|
// the package publisher's intent to make the setter required to be set.
|
||||||
Required bool
|
Required bool
|
||||||
|
|
||||||
|
RecurseSubPackages bool
|
||||||
|
|
||||||
|
OpenAPIFileName string
|
||||||
|
|
||||||
// Path to openAPI file
|
// Path to openAPI file
|
||||||
OpenAPIPath string
|
OpenAPIPath string
|
||||||
|
|
||||||
@@ -55,17 +59,21 @@ type SetterCreator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *SetterCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (c *SetterCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return nil, c.Create(c.OpenAPIPath, c.ResourcesPath)
|
return nil, c.Create()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
func (c SetterCreator) Create() error {
|
||||||
err := validateSchema(c.Schema)
|
err := c.validateSetterInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = validateSchema(c.Schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("invalid schema: %v", err)
|
return errors.Errorf("invalid schema: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the resources with the setter reference
|
// Update the resources with the setter reference
|
||||||
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath}
|
inout := &kio.LocalPackageReadWriter{PackagePath: c.ResourcesPath}
|
||||||
a := &setters2.Add{
|
a := &setters2.Add{
|
||||||
FieldName: c.FieldName,
|
FieldName: c.FieldName,
|
||||||
FieldValue: c.FieldValue,
|
FieldValue: c.FieldValue,
|
||||||
@@ -78,7 +86,7 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
Outputs: []kio.Writer{inout},
|
Outputs: []kio.Writer{inout},
|
||||||
}.Execute()
|
}.Execute()
|
||||||
if a.Count == 0 {
|
if a.Count == 0 {
|
||||||
fmt.Printf("setter %s doesn't match any field in resource configs, "+
|
fmt.Printf("setter %q doesn't match any field in resource configs, "+
|
||||||
"but creating setter definition\n", c.Name)
|
"but creating setter definition\n", c.Name)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -90,12 +98,12 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
Name: c.Name, Value: c.FieldValue, SetBy: c.SetBy, Description: c.Description,
|
Name: c.Name, Value: c.FieldValue, SetBy: c.SetBy, Description: c.Description,
|
||||||
Type: c.Type, Schema: c.Schema, Required: c.Required,
|
Type: c.Type, Schema: c.Schema, Required: c.Required,
|
||||||
}
|
}
|
||||||
if err := sd.AddToFile(openAPIPath); err != nil {
|
if err := sd.AddToFile(c.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the updated definitions
|
// Load the updated definitions
|
||||||
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
if err := openapi.AddSchemaFromFile(c.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// if the setter is of array type write the derived list values back to
|
// if the setter is of array type write the derived list values back to
|
||||||
@@ -103,7 +111,7 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
if len(a.ListValues) > 0 {
|
if len(a.ListValues) > 0 {
|
||||||
sd.ListValues = a.ListValues
|
sd.ListValues = a.ListValues
|
||||||
sd.Value = ""
|
sd.Value = ""
|
||||||
if err := sd.AddToFile(openAPIPath); err != nil {
|
if err := sd.AddToFile(c.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,3 +173,32 @@ func validateSchemaTypes(sc *spec.Schema) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c SetterCreator) validateSetterInfo() error {
|
||||||
|
// check if substitution with same name exists and throw error
|
||||||
|
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
subst, _ := openapi.Resolve(&ref)
|
||||||
|
// if substitution already exists with the input setter name, throw error
|
||||||
|
if subst != nil {
|
||||||
|
return errors.Errorf("substitution with name %q already exists, "+
|
||||||
|
"substitution and setter can't have same name", c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if setter with same name exists and throw error
|
||||||
|
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
setter, _ := openapi.Resolve(&ref)
|
||||||
|
// if setter already exists with the input setter name, throw error
|
||||||
|
if setter != nil {
|
||||||
|
return errors.Errorf("setter with name %q already exists, "+
|
||||||
|
"if you want to modify it, please delete the existing setter and recreate it", c.Name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,15 +47,23 @@ type SubstitutionCreator struct {
|
|||||||
// Path to openAPI file
|
// Path to openAPI file
|
||||||
OpenAPIPath string
|
OpenAPIPath string
|
||||||
|
|
||||||
|
OpenAPIFileName string
|
||||||
|
|
||||||
|
RecurseSubPackages bool
|
||||||
|
|
||||||
// Path to resources folder
|
// Path to resources folder
|
||||||
ResourcesPath string
|
ResourcesPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SubstitutionCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (c *SubstitutionCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return nil, c.Create(c.OpenAPIPath, c.ResourcesPath)
|
return nil, c.Create()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
func (c SubstitutionCreator) Create() error {
|
||||||
|
err := c.validateSubstitutionInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
values, err := markersAndRefs(c.Name, c.Pattern)
|
values, err := markersAndRefs(c.Name, c.Pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -70,22 +78,22 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
// the input substitution definition is updated in the openAPI file and then parsed
|
// the input substitution definition is updated in the openAPI file and then parsed
|
||||||
// to check if there are any cycles in nested substitutions, if there are
|
// to check if there are any cycles in nested substitutions, if there are
|
||||||
// any, the openAPI file will be reverted to current state and error is thrown
|
// any, the openAPI file will be reverted to current state and error is thrown
|
||||||
stat, err := os.Stat(openAPIPath)
|
stat, err := os.Stat(c.OpenAPIPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
curOpenAPI, err := ioutil.ReadFile(openAPIPath)
|
curOpenAPI, err := ioutil.ReadFile(c.OpenAPIPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.AddToFile(openAPIPath); err != nil {
|
if err := d.AddToFile(c.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the updated definitions
|
// Load the updated definitions
|
||||||
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
if err := openapi.AddSchemaFromFile(c.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,19 +113,19 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.CreateSettersForSubstitution(openAPIPath)
|
err = c.CreateSettersForSubstitution(c.OpenAPIPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the updated definitions after setters are created
|
// Load the updated definitions after setters are created
|
||||||
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
if err := openapi.AddSchemaFromFile(c.OpenAPIPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert openAPI file if there are cycles detected in created input substitution
|
// revert openAPI file if there are cycles detected in created input substitution
|
||||||
if err := checkForCycles(ext, visited); err != nil {
|
if err := checkForCycles(ext, visited); err != nil {
|
||||||
if writeErr := ioutil.WriteFile(openAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
|
if writeErr := ioutil.WriteFile(c.OpenAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
|
||||||
return writeErr
|
return writeErr
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -130,7 +138,7 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the resources with the substitution reference
|
// Update the resources with the substitution reference
|
||||||
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath}
|
inout := &kio.LocalPackageReadWriter{PackagePath: c.ResourcesPath}
|
||||||
err = kio.Pipeline{
|
err = kio.Pipeline{
|
||||||
Inputs: []kio.Reader{inout},
|
Inputs: []kio.Reader{inout},
|
||||||
Filters: []kio.Filter{kio.FilterAll(a)},
|
Filters: []kio.Filter{kio.FilterAll(a)},
|
||||||
@@ -203,7 +211,7 @@ func (c SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) er
|
|||||||
// continue if ref is a substitution, as it has already been checked if it exists
|
// continue if ref is a substitution, as it has already been checked if it exists
|
||||||
// as part of preRunE
|
// as part of preRunE
|
||||||
if strings.Contains(value.Ref, fieldmeta.SubstitutionDefinitionPrefix) {
|
if strings.Contains(value.Ref, fieldmeta.SubstitutionDefinitionPrefix) {
|
||||||
fmt.Printf("found a substitution with name %s\n", value.Marker)
|
fmt.Printf("found a substitution with name %q\n", value.Marker)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
setterObj, err := y.Pipe(yaml.Lookup(
|
setterObj, err := y.Pipe(yaml.Lookup(
|
||||||
@@ -420,3 +428,32 @@ func min(a int, b int) int {
|
|||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c SubstitutionCreator) validateSubstitutionInfo() error {
|
||||||
|
// check if substitution with same name exists and throw error
|
||||||
|
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
subst, _ := openapi.Resolve(&ref)
|
||||||
|
// if substitution already exists with the input substitution name, throw error
|
||||||
|
if subst != nil {
|
||||||
|
return errors.Errorf("substitution with name %q already exists", c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if setter with same name exists and throw error
|
||||||
|
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + c.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
setter, _ := openapi.Resolve(&ref)
|
||||||
|
// if setter already exists with input substitution name, throw error
|
||||||
|
if setter != nil {
|
||||||
|
return errors.Errorf(fmt.Sprintf("setter with name %q already exists, "+
|
||||||
|
"substitution and setter can't have same name", c.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user