Compare commits

...

100 Commits

Author SHA1 Message Date
Jeff Regan
3514317b3d Merge pull request #3007 from monopole/unpin
Unpin the dependencies post release.
2020-09-18 11:19:42 -07:00
Jeff Regan
9299821571 Merge pull request #2998 from Shell32-Natsu/network
Change network to a boolean in kpt fn run
2020-09-18 11:12:26 -07:00
Jeffrey Regan
d91f313137 Unpin the dependencies post release. 2020-09-18 09:51:05 -07:00
Jeff Regan
161af9d99c Merge pull request #3002 from monopole/pinToApiV0_6_1
Pin to api/v0.6.1
2020-09-17 17:18:11 -07:00
jregan
b115c95ea1 Pin to api/v0.6.1 2020-09-17 16:27:08 -07:00
Jeff Regan
20cd4bfef9 Merge pull request #2997 from kubernetes-sigs/removeReplaceDir
Update go.mod
2020-09-17 11:02:08 -07:00
Donny Xia
f6c06b58ef Change network to a boolean 2020-09-16 16:20:50 -07:00
Jeff Regan
c45e05b7bd Update go.mod 2020-09-16 12:53:39 -07:00
Kubernetes Prow Robot
76bae738a0 Merge pull request #2932 from mstrYoda/master
add DisableNameSuffixHash parameter to edit Secret & ConfigMap
2020-09-16 10:29:20 -07:00
Jeff Regan
0770661b2a Merge pull request #2991 from monopole/goSumUpdates
Go sum updates
2020-09-15 17:34:23 -07:00
jregan
67d5871e87 Go sum updates 2020-09-15 17:02:40 -07:00
Jeff Regan
f98c683915 Merge pull request #2983 from Shell32-Natsu/allow-null
ignore null value in fieldspec
2020-09-15 17:02:20 -07:00
Jeff Regan
ffe9c9d947 Merge pull request #2990 from monopole/pinToKyamlv0_8_0
Pin to kyaml v0.8.0
2020-09-15 15:51:08 -07:00
jregan
4d42ffc7f8 Pin to kyaml v0.8.0 2020-09-15 15:26:29 -07:00
Jeff Regan
d7dc7d911e Merge pull request #2989 from monopole/minorFix
Generated changes.
2020-09-15 14:56:16 -07:00
jregan
04404ff61b Generated changes. 2020-09-15 14:55:08 -07:00
Jeff Regan
f864e15c68 Merge pull request #2974 from Shell32-Natsu/function-definition
remove not used args & use const string instead of literal
2020-09-15 14:34:25 -07:00
Jeff Regan
29a444fffc Merge pull request #2988 from Shell32-Natsu/env-flag
Add --env/-e flag to fn run
2020-09-15 14:31:40 -07:00
Donny Xia
327035a43a Add --env/-e flag 2020-09-15 11:49:26 -07:00
Kubernetes Prow Robot
ad7fed061e Merge pull request #2984 from phanimarupaka/FixCmdCfgIssues
Do not print package info in grep
2020-09-15 09:40:07 -07:00
Phani Teja Marupaka
cea2986574 Don not pring package info in grep 2020-09-15 00:15:52 -07:00
Kubernetes Prow Robot
00f0fd7109 Merge pull request #2978 from mortent/NamespaceabilityFromSchema
Determine namespaceability of resources from openapi schema
2020-09-14 21:10:06 -07:00
Kubernetes Prow Robot
1c6481d011 Merge pull request #2982 from mortent/UpdateCliUtils
Update cmd/config to use latest version of cli-utils
2020-09-14 13:27:24 -07:00
Donny Xia
f0bc926640 ignore null value in fieldspec 2020-09-14 13:20:20 -07:00
Morten Torkildsen
11d9ff5690 Update cmd/config to use latest version of cli-utils 2020-09-14 12:08:48 -07:00
Jeff Regan
6a0a909e73 Merge pull request #2976 from monopole/deferLive
Remove live; done testing.  Bring to sig-cli for discussion.
2020-09-14 11:00:48 -07:00
Kubernetes Prow Robot
bd8f0c88e5 Merge pull request #2967 from phanimarupaka/CfgTreeWithSubpackages
Print Krmfile data for cfg tree
2020-09-14 10:42:59 -07:00
Donny Xia
e5809e49cb remove not used args 2020-09-14 10:10:20 -07:00
Phani Teja Marupaka
880009b648 Print Krmfile data for cfg tree 2020-09-14 09:57:18 -07:00
Morten Torkildsen
d083c7f1d0 Determine namespaceability of resources from openapi schema 2020-09-12 15:01:42 -07:00
Jeffrey Regan
684ce141de Defer live testing. 2020-09-11 17:25:25 -07:00
Kubernetes Prow Robot
5c8c7a043a Merge pull request #2973 from phanimarupaka/CfgCommandsStdoutFixes
Format the output of cfg commands
2020-09-11 16:44:57 -07:00
Kubernetes Prow Robot
0fe7f65ef2 Merge pull request #2975 from monopole/addTest
Add test representing 2960
2020-09-11 16:10:57 -07:00
Jeffrey Regan
950c1de46d Add test representing 2960 2020-09-11 15:22:41 -07:00
Phani Teja Marupaka
fc690f14a8 Format the output of cfg commands 2020-09-11 14:49:18 -07:00
Jeff Regan
a6e03e4d11 Merge pull request #2920 from wyyxd2017/hato4
Technical details structure picture
2020-09-11 14:32:19 -07:00
Jeff Regan
60428be5fb Merge pull request #2944 from justinsb/alas_poor_grepfilter
Remove some obsolete references to GrepFilter
2020-09-11 14:16:30 -07:00
Jeff Regan
4d402d4875 Merge pull request #2969 from justinsb/fix_split_docs
Fix comment on SplitIndexNameValue
2020-09-11 14:13:43 -07:00
Jeff Regan
fbddd264be Merge pull request #2971 from etefera/fix-broken-patches-change
Fix unintended patches change in all Kustomization writes.
2020-09-11 13:33:09 -07:00
Eyob Tefera
d3c46d3f7c Move offending Write() tests to tests for fix. 2020-09-11 19:19:54 +00:00
Eyob Tefera
dda3984a8f Move kustomization fixing to before Write step. 2020-09-11 18:57:14 +00:00
Eyob Tefera
f889ca8885 Add set image test with patchesJson6902. 2020-09-11 18:48:48 +00:00
Justin SB
341bacb9a2 Fix comment on SplitIndexNameValue
It was incorrect and suggested some behaviour which isn't present.
Added test to verify the documented behaviour.
2020-09-11 11:39:49 -04:00
Kubernetes Prow Robot
badc1177d9 Merge pull request #2939 from ZhuGongpu/master
Add --log-steps flag
2020-09-09 19:05:44 -07:00
Kubernetes Prow Robot
1680cc72c0 Merge pull request #2953 from easimon/add_namespace_to_namespace_transformer
Add namespace name to namespace transformer defaults
2020-09-09 14:57:44 -07:00
Jeff Regan
2f89de86f8 Merge pull request #2956 from justinsb/fix_language
Replace language with more inclusive & accurate "hard-coded"
2020-09-09 11:33:53 -07:00
Jeff Regan
ab4e9c718b Merge pull request #2943 from Shell32-Natsu/clean-up-temp-dir
remove all temp dir
2020-09-09 11:20:17 -07:00
Kubernetes Prow Robot
288c03ddca Merge pull request #2959 from phanimarupaka/CatWithSubpkgs
Cat with subpackages
2020-09-09 10:49:08 -07:00
Justin SB
5c60285f25 Replace language with more inclusive & accurate "hard-coded"
hard-coded is probably more helpful to understanding the limitations
of the current approach.
2020-09-09 08:41:33 -04:00
Kubernetes Prow Robot
6df0a45368 Merge pull request #2958 from phanimarupaka/GrepWithSubpkgs
Grep with subpackages
2020-09-08 21:09:52 -07:00
Kubernetes Prow Robot
8206987580 Merge pull request #2957 from phanimarupaka/CountWithSubpkgs
Count with Subpackages
2020-09-08 20:53:52 -07:00
Kubernetes Prow Robot
6189ca9798 Merge pull request #2955 from phanimarupaka/FmtWithSubpkgs
Fmt with subpackages
2020-09-08 20:33:52 -07:00
Phani Teja Marupaka
b8c1601a93 Cat with subpackages 2020-09-08 18:42:31 -07:00
Phani Teja Marupaka
34d610a38d Fmt with subpackages 2020-09-08 17:07:55 -07:00
Phani Teja Marupaka
8e4c8464e7 Grep with subpackages 2020-09-08 16:59:23 -07:00
Phani Teja Marupaka
43ab7a8e71 Count with Subpackages 2020-09-08 16:33:00 -07:00
Kubernetes Prow Robot
d2f23a4b8b Merge pull request #2938 from phanimarupaka/OtherCfgCommandsWithSubPkgs
annotate, delete-setter, delete-subst With Subpackages
2020-09-08 16:25:52 -07:00
Phani Teja Marupaka
0dc36a4f7c Annotate With Subpackages
Delete Setters And Subst With Subpkgs
2020-09-08 15:52:57 -07:00
Kubernetes Prow Robot
678ae12115 Merge pull request #2946 from phanimarupaka/RefactorSubPkgsIteration
Refactor subpackages logic
2020-09-08 11:47:52 -07:00
Phani Teja Marupaka
c4d937322f Refactor subpackages logic 2020-09-08 11:23:54 -07:00
Kubernetes Prow Robot
a2adb835b6 Merge pull request #2941 from mortent/FixIgnoreFilesMatcher
Fix issue where ignoreFilesMatcher doesn't work correctly
2020-09-08 10:33:44 -07:00
Markus Dobel
01b5c4e9da Add namespace name to namespace transformer defaults 2020-09-08 11:24:58 +02:00
Justin SB
eb4c5dc035 Remove some obsolete references to GrepFilter
Looks like GrepFilter was generalized to Filter.
2020-09-04 13:41:16 -04:00
Morten Torkildsen
e976386931 Fix issue where ignoreFilesMatcher doesn't work correctly 2020-09-03 20:14:07 -07:00
Donny Xia
bae9986422 remove all temp dir 2020-09-03 12:03:12 -07:00
Jeff Regan
e7970d82a8 Merge pull request #2942 from Shell32-Natsu/addDonny
add Donny to maintainer
2020-09-03 11:52:14 -07:00
Donny Xia
9bdd489c96 add Donny to maintainer 2020-09-03 10:57:50 -07:00
Kubernetes Prow Robot
0f49fef5ed Merge pull request #2940 from phanimarupaka/FixSettersSubPkgsFriction
Fix setters subpkgs friction
2020-09-03 08:59:41 -07:00
Phani Teja Marupaka
8d74b8c3b5 Fix setters subpkgs friction 2020-09-02 23:06:26 -07:00
Gongpu Zhu
39a8798a87 Add --log-steps flag 2020-09-02 20:47:21 -07:00
Jeff Regan
980f407552 Merge pull request #2931 from Shell32-Natsu/image-tag-legacy
add legacy filter to image tag transformer
2020-09-02 13:02:53 -07:00
Donny Xia
9ca8f4602d add legacy filter to image tag transformer 2020-09-01 13:06:14 -07:00
Kubernetes Prow Robot
ba0f583ee5 Merge pull request #2911 from phanimarupaka/SetWithSubPackages
Setters/substitutions with subpackages
2020-09-01 11:23:51 -07:00
Phani Teja Marupaka
f432f4d75e Setters with subpackages 2020-09-01 10:54:08 -07:00
Jeff Regan
17793abacd Merge pull request #2930 from daniel-hutao/patch-1
fix “chart s” to “charts ”
2020-09-01 10:12:58 -07:00
Jeff Regan
64cd4ec1d5 Merge pull request #2929 from monopole/testExamplesAgainst_v3.8.2
Test examples against v3.8.2
2020-09-01 10:12:18 -07:00
Daniel (ht)
fb822984e3 fix “chart s” to “charts ”
fix “chart s” to “charts ”
2020-09-01 16:24:49 +08:00
jregan
6d2a737c29 Test examples against v3.8.2 2020-08-31 16:48:19 -07:00
Jeff Regan
6e7713281e Merge pull request #2928 from monopole/addGorepomod
Add more release instructions
2020-08-31 13:50:48 -07:00
jregan
6a7bb9e33e Add gorepomod tool to install list 2020-08-31 13:28:19 -07:00
Jeff Regan
0e9428c8b0 Merge pull request #2927 from monopole/unpinning
Unpinning after release releases
2020-08-31 12:47:28 -07:00
jregan
c838962432 fix module hashes 2020-08-31 12:08:16 -07:00
jregan
548d10ef08 unpin kyaml 2020-08-31 12:08:16 -07:00
jregan
2db8487f02 unpin cmd/config 2020-08-31 12:08:16 -07:00
jregan
b42f71a20f unpin api 2020-08-31 12:08:16 -07:00
Jeff Regan
e9824aa749 Merge pull request #2926 from monopole/fixAGoMod
Repair a go module spec.
2020-08-31 12:08:06 -07:00
jregan
92cc9fc5e1 Repair a go module spec. 2020-08-31 11:35:32 -07:00
wangyeyu
e53b4c9884 Technical details structure picture 2020-08-31 10:01:19 +08:00
Jeff Regan
e2973f6ecc Merge pull request #2915 from monopole/pinToKustomizeApiv_0_6_0
Pin to kustomize api v0.6.0
2020-08-29 09:42:26 -07:00
jregan
2bf9fc816d Pin to kustomize api v0.6.0 2020-08-29 08:55:29 -07:00
Jeff Regan
ff55856c63 Merge pull request #2913 from monopole/pinApiToKyamlV_0_7_1
Pin api to kyaml/v0.7.1
2020-08-28 19:23:36 -07:00
jregan
ceef219eec Pin api to kyaml/v0.7.1 2020-08-28 18:54:41 -07:00
Jeff Regan
b21699a277 Merge pull request #2912 from monopole/pinCmdConfigToKyamlv0_7_1
Pin to cmd/config to kyaml/v0.7.1 and cli-utils/v0.19.2
2020-08-28 18:47:00 -07:00
jregan
2ab85d2f63 Pin to cmd/config to kyaml/v0.7.1 and cli-utils/v0.19.2 2020-08-28 18:25:14 -07:00
Kubernetes Prow Robot
320545884c Merge pull request #2898 from mortent/AddKrmignoreFile
Add support for .krmignore file
2020-08-28 18:17:19 -07:00
Morten Torkildsen
16bbc2d67e Add support for .krmignore file 2020-08-28 17:28:02 -07:00
Jeff Regan
6d860e8ace Merge pull request #2910 from monopole/updateReleaseInstructions
Add recommended sequence to release instructions.
2020-08-28 11:45:58 -07:00
Jeffrey Regan
80c8a6df61 Add recommended sequence to release instructions. 2020-08-28 11:43:34 -07:00
mstrYoda
257707d839 Merge branch 'master' of https://github.com/kubernetes-sigs/kustomize 2020-08-26 13:24:04 +03:00
mstrYoda
c1cd872df6 add DisableNameSuffixHash for secret and configmap 2020-08-26 13:22:26 +03:00
174 changed files with 72094 additions and 5828 deletions

View File

@@ -15,7 +15,8 @@ verify-kustomize: \
lint-kustomize \ lint-kustomize \
test-unit-kustomize-all \ test-unit-kustomize-all \
test-examples-kustomize-against-HEAD \ test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.0 test-examples-kustomize-against-3.8.0 \
test-examples-kustomize-against-3.8.2
# The following target referenced by a file in # The following target referenced by a file in
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize # https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
@@ -26,7 +27,8 @@ prow-presubmit-check: \
test-unit-cmd-all \ test-unit-cmd-all \
test-go-mod \ test-go-mod \
test-examples-kustomize-against-HEAD \ test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.0 test-examples-kustomize-against-3.8.0 \
test-examples-kustomize-against-3.8.2
.PHONY: verify-kustomize-e2e .PHONY: verify-kustomize-e2e
verify-kustomize-e2e: test-examples-e2e-kustomize verify-kustomize-e2e: test-examples-e2e-kustomize
@@ -45,17 +47,18 @@ $(MYGOBIN)/golangci-lint-kustomize:
GO111MODULE=on go build -tags=tools -o $(MYGOBIN)/golangci-lint-kustomize github.com/golangci/golangci-lint/cmd/golangci-lint; \ GO111MODULE=on go build -tags=tools -o $(MYGOBIN)/golangci-lint-kustomize github.com/golangci/golangci-lint/cmd/golangci-lint; \
) )
# Version pinned by api/go.mod $(MYGOBIN)/gorepomod:
cd api; \
go install github.com/monopole/gorepomod
$(MYGOBIN)/mdrip: $(MYGOBIN)/mdrip:
cd api; \ cd api; \
go install github.com/monopole/mdrip go install github.com/monopole/mdrip
# Version pinned by api/go.mod
$(MYGOBIN)/stringer: $(MYGOBIN)/stringer:
cd api; \ cd api; \
go install golang.org/x/tools/cmd/stringer go install golang.org/x/tools/cmd/stringer
# Version pinned by api/go.mod
$(MYGOBIN)/goimports: $(MYGOBIN)/goimports:
cd api; \ cd api; \
go install golang.org/x/tools/cmd/goimports go install golang.org/x/tools/cmd/goimports
@@ -81,6 +84,7 @@ $(MYGOBIN)/kustomize:
install-tools: \ install-tools: \
$(MYGOBIN)/goimports \ $(MYGOBIN)/goimports \
$(MYGOBIN)/golangci-lint-kustomize \ $(MYGOBIN)/golangci-lint-kustomize \
$(MYGOBIN)/gorepomod \
$(MYGOBIN)/mdrip \ $(MYGOBIN)/mdrip \
$(MYGOBIN)/pluginator \ $(MYGOBIN)/pluginator \
$(MYGOBIN)/stringer $(MYGOBIN)/stringer
@@ -245,6 +249,19 @@ test-examples-kustomize-against-3.8.0: $(MYGOBIN)/mdrip
cd kustomize; go install .; \ cd kustomize; go install .; \
) )
.PHONY:
test-examples-kustomize-against-3.8.2: $(MYGOBIN)/mdrip
( \
set -e; \
tag=v3.8.2; \
/bin/rm -f $(MYGOBIN)/kustomize; \
echo "Installing kustomize $$tag."; \
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
./hack/testExamplesAgainstKustomize.sh $$tag; \
echo "Reinstalling kustomize from HEAD."; \
cd kustomize; go install .; \
)
# linux only. # linux only.
# This is for testing an example plugin that # This is for testing an example plugin that
# uses kubeval for validation. # uses kubeval for validation.

View File

@@ -11,3 +11,4 @@ aliases:
- pwittrock - pwittrock
- mortent - mortent
- phanimarupaka - phanimarupaka
- Shell32-Natsu

View File

@@ -31,14 +31,15 @@ func (p *ImageTagTransformerPlugin) Config(
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error { func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
for _, r := range m.Resources() { for _, r := range m.Resources() {
// If you're here because someone expected any field containing // traverse all fields at first
// the string "containers" or "initContainers" to get an image err := filtersutil.ApplyToJSON(imagetag.LegacyFilter{
// update (not just spec/template/spec/containers[], etc.) then ImageTag: p.ImageTag,
// a code change is needed. See api/filters/imagetag/legacy }, r)
// for the start of an implementation that won't use an if err != nil {
// allowlist like FsSlice, and instead walks the object looking return err
// for fields named containers or initContainers. }
err := filtersutil.ApplyToJSON(imagetag.Filter{ // then use user specified field specs
err = filtersutil.ApplyToJSON(imagetag.Filter{
ImageTag: p.ImageTag, ImageTag: p.ImageTag,
FsSlice: p.FieldSpecs, FsSlice: p.FieldSpecs,
}, r) }, r)

View File

@@ -51,6 +51,9 @@ func (fltr Filter) filter(obj *yaml.RNode) error {
// found the field -- set its value // found the field -- set its value
return fltr.SetValue(obj) return fltr.SetValue(obj)
} }
if obj.IsTaggedNull() {
return nil
}
switch obj.YNode().Kind { switch obj.YNode().Kind {
case yaml.SequenceNode: case yaml.SequenceNode:
return fltr.seq(obj) return fltr.seq(obj)
@@ -67,7 +70,7 @@ func (fltr Filter) field(obj *yaml.RNode) error {
// lookup the field matching the next path element // lookup the field matching the next path element
var lookupField yaml.Filter var lookupField yaml.Filter
var kind yaml.Kind var kind yaml.Kind
tag := "" // TODO: change to yaml.NodeTagEmpty tag := yaml.NodeTagEmpty
switch { switch {
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq: case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
// dont' create the field if we don't find it // dont' create the field if we don't find it
@@ -95,9 +98,10 @@ func (fltr Filter) field(obj *yaml.RNode) error {
return errors.WrapPrefixf(err, "fieldName: %s", fieldName) return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
} }
// if the value exists, but is null, then change it to the creation type // if the value exists, but is null and kind is set,
// then change it to the creation type
// TODO: update yaml.LookupCreate to support this // TODO: update yaml.LookupCreate to support this
if field.YNode().Tag == yaml.NodeTagNull { if field.YNode().Tag == yaml.NodeTagNull && yaml.IsCreate(kind) {
field.YNode().Kind = kind field.YNode().Kind = kind
field.YNode().Tag = tag field.YNode().Tag = tag
} }

View File

@@ -433,7 +433,6 @@ spec:
SetValue: filtersutil.SetScalar("bar"), SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode, CreateKind: yaml.ScalarNode,
}, },
error: "obj '' at path 'spec/containers/image': expected sequence or mapping node",
}, },
{ {
name: "filedname with slash '/'", name: "filedname with slash '/'",

View File

@@ -168,6 +168,44 @@ metadata:
map: map:
name: newName name: newName
namespace: oldNs namespace: oldNs
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"null value": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: null
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: NotSecret
metadata:
name: newName2
`,
originalNames: []string{"oldName", ""},
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: null
`, `,
filter: Filter{ filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"}, FieldSpec: types.FieldSpec{Path: "map"},
@@ -217,27 +255,6 @@ func TestNamerefFilterUnhappy(t *testing.T) {
filter Filter filter Filter
originalNames []string originalNames []string
}{ }{
"invalid node type": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: null
`,
candidates: "",
originalNames: []string{},
expected: "obj '' at path 'ref/name': node is expected to be either a string or a slice of string or a map of string",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"multiple match": { "multiple match": {
input: ` input: `
apiVersion: apps/v1 apiVersion: apps/v1

View File

@@ -69,7 +69,7 @@ func (ns Filter) hacks(obj *yaml.RNode) error {
// metaNamespaceHack is a hack for implementing the namespace transform // metaNamespaceHack is a hack for implementing the namespace transform
// for the metadata.namespace field on namespace scoped resources. // for the metadata.namespace field on namespace scoped resources.
// namespace scoped resources are determined by NOT being present // namespace scoped resources are determined by NOT being present
// in a blacklist of cluster-scoped resource types (by apiVersion and kind). // in a hard-coded list of cluster-scoped resource types (by apiVersion and kind).
// //
// This hack should be updated to allow individual resources to specify // This hack should be updated to allow individual resources to specify
// if they are cluster scoped through either an annotation on the resources, // if they are cluster scoped through either an annotation on the resources,

View File

@@ -188,6 +188,26 @@ data:
FieldSpec: types.FieldSpec{Path: "data/slice2"}, FieldSpec: types.FieldSpec{Path: "data/slice2"},
}, },
}, },
"null value": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}),
FieldSpec: types.FieldSpec{Path: "data/FOO"},
},
},
} }
for tn, tc := range testCases { for tn, tc := range testCases {
@@ -260,20 +280,6 @@ data:
FieldSpec: types.FieldSpec{Path: "data"}, FieldSpec: types.FieldSpec{Path: "data"},
}, },
}, },
"null input": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
expectedError: "obj '' at path 'data/FOO': invalid type encountered 0",
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}),
FieldSpec: types.FieldSpec{Path: "data/FOO"},
},
},
} }
for tn, tc := range testCases { for tn, tc := range testCases {

View File

@@ -10,15 +10,13 @@ require (
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0
github.com/yujunz/go-getter v1.4.1-lite github.com/yujunz/go-getter v1.4.1-lite
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
k8s.io/api v0.17.0 k8s.io/api v0.17.0
k8s.io/apimachinery v0.17.0 k8s.io/apimachinery v0.17.0
k8s.io/client-go v0.17.0 k8s.io/client-go v0.17.0
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
sigs.k8s.io/kustomize/kyaml v0.6.1 sigs.k8s.io/kustomize/kyaml v0.8.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )
replace sigs.k8s.io/kustomize/kyaml v0.6.1 => ../kyaml

View File

@@ -307,6 +307,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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -526,6 +528,8 @@ golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -584,6 +588,8 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphD
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 h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
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/kustomize/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=

View File

@@ -132,7 +132,7 @@ func TestRefVarTransformer(t *testing.T) {
' at path 'data/slice': invalid value type expect a string`, ' at path 'data/slice': invalid value type expect a string`,
}, },
{ {
description: "var replacement panic in nil", description: "var replacement in nil",
given: given{ given: given{
varMap: map[string]interface{}{}, varMap: map[string]interface{}{},
fs: []types.FieldSpec{ fs: []types.FieldSpec{
@@ -150,7 +150,19 @@ func TestRefVarTransformer(t *testing.T) {
"nil": nil, // noticeably *not* a []string "nil": nil, // noticeably *not* a []string
}}).ResMap(), }}).ResMap(),
}, },
errMessage: `obj '' at path 'data/nil': invalid type encountered 0`, expected: expected{
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
"data": map[string]interface{}{
"nil": nil, // noticeably *not* a []string
}}).ResMap(),
},
}, },
} }

View File

@@ -217,7 +217,7 @@ overview of each component with the following sections going into more details.
The overall structure is outlined in the following figure: The overall structure is outlined in the following figure:
![overview]( ![overview](
https://sigs.k8s.io/kustomize/internal/tools/pictures/sys_arch.png) https://github.com/kubernetes-sigs/kustomize/blob/master/api/internal/crawl/pictures/token_config.png)
#### Crawler #### Crawler
The leftmost component consists of a crawler with an http cache of GitHub The leftmost component consists of a crawler with an http cache of GitHub

View File

@@ -271,6 +271,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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -470,6 +472,7 @@ golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -524,8 +527,8 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
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/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak= sigs.k8s.io/kustomize/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI= sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -65,8 +65,8 @@ func TestLoader(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
for _, behavior := range []types.BuiltinPluginLoadingOptions{ for _, behavior := range []types.BuiltinPluginLoadingOptions{
types.BploUseStaticallyLinked, /* types.BploUseStaticallyLinked,
types.BploLoadFromFileSys} { types.BploLoadFromFileSys */} {
c, err := konfig.EnabledPluginConfig(behavior) c, err := konfig.EnabledPluginConfig(behavior)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@@ -8,6 +8,9 @@ const (
namespace: namespace:
- path: metadata/namespace - path: metadata/namespace
create: true create: true
- path: metadata/name
kind: Namespace
create: true
- path: subjects - path: subjects
kind: RoleBinding kind: RoleBinding
- path: subjects - path: subjects

View File

@@ -9,7 +9,7 @@ import (
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest" kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
) )
func TestNullValues(t *testing.T) { func TestNullValues1(t *testing.T) {
th := kusttest_test.MakeHarness(t) th := kusttest_test.MakeHarness(t)
th.WriteF("/app/deployment.yaml", ` th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1 apiVersion: apps/v1
@@ -62,3 +62,36 @@ spec:
name: example name: example
`) `)
} }
func TestNullValues2(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("deploy.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
volumes: null
`)
th.WriteK(".", `
resources:
- deploy.yaml
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
volumes: null
`)
}

View File

@@ -215,25 +215,25 @@ spec2:
template: template:
spec: spec:
containers: containers:
- image: nginx:v1 - image: nginx:v2
name: nginx3 name: nginx3
- image: my-nginx:latest - image: my-nginx:previous
name: nginx4 name: nginx4
spec3: spec3:
template: template:
spec: spec:
initContainers: initContainers:
- image: postgres:alpine-9 - image: my-postgres:v3
name: postgresdb name: postgresdb
- image: docker:17-git - image: my-docker@sha256:25a0d4b4
name: init-docker name: init-docker
- image: myprivaterepohostname:1234/my/image:latest - image: myprivaterepohostname:1234/my/image:v1.0.1
name: myImage name: myImage
- image: myprivaterepohostname:1234/my/image - image: myprivaterepohostname:1234/my/image:v1.0.1
name: myImage2 name: myImage2
- image: my-app-image:v1 - image: my-app-image:v1
name: my-app name: my-app
- image: gcr.io:8080/my-project/my-cool-app:latest - image: my-cool-app:latest
name: my-cool-app name: my-cool-app
`) `)
} }

View File

@@ -20,6 +20,9 @@ type remoteTargetSpec struct {
// Dir is where the resource is saved // Dir is where the resource is saved
Dir filesys.ConfirmedDir Dir filesys.ConfirmedDir
// TempDir is the directory created to hold all resources, including Dir
TempDir filesys.ConfirmedDir
} }
// Getter is a function that can gets resource // Getter is a function that can gets resource
@@ -31,7 +34,7 @@ func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader
} }
cleaner := func() error { cleaner := func() error {
return fSys.RemoveAll(rs.Dir.String()) return fSys.RemoveAll(rs.TempDir.String())
} }
if err := getter(rs); err != nil { if err := getter(rs); err != nil {
@@ -55,12 +58,12 @@ func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader
func getRemoteTarget(rs *remoteTargetSpec) error { func getRemoteTarget(rs *remoteTargetSpec) error {
var err error var err error
rs.Dir, err = filesys.NewTmpConfirmedDir() rs.TempDir, err = filesys.NewTmpConfirmedDir()
if err != nil { if err != nil {
return err return err
} }
rs.Dir = filesys.ConfirmedDir(rs.Dir.Join("repo")) rs.Dir = filesys.ConfirmedDir(rs.TempDir.Join("repo"))
// Get the pwd // Get the pwd
pwd, err := os.Getwd() pwd, err := os.Getwd()

View File

@@ -39,7 +39,7 @@ var (
ExitOnError = &commands.ExitOnError ExitOnError = &commands.ExitOnError
) )
// AddCommands adds the cfg, fn and live commands to kustomize. // AddCommands adds the cfg and fn commands to kustomize.
func AddCommands(root *cobra.Command, name string) *cobra.Command { func AddCommands(root *cobra.Command, name string) *cobra.Command {
commands.ExitOnError = true commands.ExitOnError = true
@@ -48,7 +48,6 @@ func AddCommands(root *cobra.Command, name string) *cobra.Command {
root.AddCommand(GetCfg(name)) root.AddCommand(GetCfg(name))
root.AddCommand(GetFn(name)) root.AddCommand(GetFn(name))
root.AddCommand(GetLive(name))
root.AddCommand(&cobra.Command{ root.AddCommand(&cobra.Command{
Use: "docs-merge", Use: "docs-merge",

View File

@@ -53,7 +53,7 @@ func GetLive(name string) *cobra.Command {
cmd.AddCommand( cmd.AddCommand(
applyCmd, applyCmd,
initcmd.NewCmdInit(ioStreams), initcmd.NewCmdInit(f, ioStreams),
preview.GetPreviewRunner(f, ioStreams).Command, preview.GetPreviewRunner(f, ioStreams).Command,
diff.NewCmdDiff(f, ioStreams), diff.NewCmdDiff(f, ioStreams),
destroy.GetDestroyRunner(f, ioStreams).Command) destroy.GetDestroyRunner(f, ioStreams).Command)

View File

@@ -14,8 +14,6 @@ require (
k8s.io/cli-runtime v0.17.3 k8s.io/cli-runtime v0.17.3
k8s.io/client-go v0.17.3 k8s.io/client-go v0.17.3
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd
sigs.k8s.io/cli-utils v0.19.0 sigs.k8s.io/cli-utils v0.20.1
sigs.k8s.io/kustomize/kyaml v0.6.1 sigs.k8s.io/kustomize/kyaml v0.8.0
) )
replace sigs.k8s.io/kustomize/kyaml => ../../kyaml

View File

@@ -283,6 +283,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/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=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -615,12 +617,14 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
sigs.k8s.io/cli-utils v0.19.0 h1:lAoR5okhSV/dIusodaQp5VbDpHMcKnvjqKYHU+AB3a4= sigs.k8s.io/cli-utils v0.20.1 h1:S3IM4Rmely9oWNAeytx46PhngTwdRxsJ4ixtoGWPc3o=
sigs.k8s.io/cli-utils v0.19.0/go.mod h1:B7KdqkSkHNIUn3cFbaR4aKUZMKtr+Benboi1w/HW/Fg= sigs.k8s.io/cli-utils v0.20.1/go.mod h1:fQkEMmLXduMNmUf1+dgQ5GRJa4OrrLMw3qzAN8YXAU8=
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/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=

View File

@@ -4,9 +4,12 @@
package commands package commands
import ( import (
"fmt"
"io"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"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/kio" "sigs.k8s.io/kustomize/kyaml/kio"
@@ -31,6 +34,8 @@ func NewAnnotateRunner(parent string) *AnnotateRunner {
c.Flags().StringVar(&r.Name, "name", "", "Resource name to annotate") c.Flags().StringVar(&r.Name, "name", "", "Resource name to annotate")
c.Flags().StringVar(&r.Namespace, "namespace", "", "Resource namespace to annotate") c.Flags().StringVar(&r.Namespace, "namespace", "", "Resource namespace to annotate")
c.Flags().StringSliceVar(&r.Values, "kv", []string{}, "annotation as KEY=VALUE") c.Flags().StringSliceVar(&r.Values, "kv", []string{}, "annotation as KEY=VALUE")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"add annotations recursively in all the nested subpackages")
return r return r
} }
@@ -39,13 +44,14 @@ func AnnotateCommand(parent string) *cobra.Command {
} }
type AnnotateRunner struct { type AnnotateRunner struct {
Command *cobra.Command Command *cobra.Command
Values []string Values []string
Kind string Kind string
Name string Name string
ApiVersion string ApiVersion string
Namespace string Namespace string
Path string Path string
RecurseSubPackages bool
} }
func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error { func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
@@ -55,16 +61,54 @@ func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
rw := &kio.ByteReadWriter{Reader: c.InOrStdin(), Writer: c.OutOrStdout()} rw := &kio.ByteReadWriter{Reader: c.InOrStdin(), Writer: c.OutOrStdout()}
input = []kio.Reader{rw} input = []kio.Reader{rw}
output = []kio.Writer{rw} output = []kio.Writer{rw}
} else {
rw := &kio.LocalPackageReadWriter{PackagePath: args[0], NoDeleteFiles: true} return handleError(c, kio.Pipeline{
input = []kio.Reader{rw} Inputs: input,
output = []kio.Writer{rw} Filters: []kio.Filter{r},
Outputs: output,
}.Execute())
} }
return handleError(c, kio.Pipeline{
e := executeCmdOnPkgs{
writer: c.OutOrStdout(),
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[0],
}
err := e.execute()
if err != nil {
return err
}
return nil
}
func (r *AnnotateRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
rw := &kio.LocalPackageReadWriter{PackagePath: pkgPath, NoDeleteFiles: true, PackageFileName: openAPIFileName}
input := []kio.Reader{rw}
output := []kio.Writer{rw}
err = kio.Pipeline{
Inputs: input, Inputs: input,
Filters: []kio.Filter{r}, Filters: []kio.Filter{r},
Outputs: output, Outputs: output,
}.Execute()) }.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprint(w, "added annotations in the package\n")
}
return nil
} }
func (r *AnnotateRunner) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { func (r *AnnotateRunner) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {

View File

@@ -12,7 +12,9 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/openapi"
) )
func TestAnnotateCommand(t *testing.T) { func TestAnnotateCommand(t *testing.T) {
@@ -486,3 +488,77 @@ spec:
replicas: 3 replicas: 3
` `
) )
func TestAnnotateSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "annotate-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"--kv", "foo=bar", "-R"},
expected: `${baseDir}/mysql/
added annotations in the package
${baseDir}/mysql/storage/
added annotations in the package
`,
},
{
name: "annotate-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
args: []string{"--kv", "foo=bar"},
expected: `${baseDir}/mysql/
added annotations in the package
`,
},
{
name: "annotate-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"--kv", "foo=bar"},
expected: `${baseDir}/mysql/storage/
added annotations in the package
`,
},
}
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 := NewAnnotateRunner("")
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, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -5,9 +5,11 @@ package commands
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"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/kio" "sigs.k8s.io/kustomize/kyaml/kio"
@@ -19,15 +21,14 @@ import (
func GetCatRunner(name string) *CatRunner { func GetCatRunner(name string) *CatRunner {
r := &CatRunner{} r := &CatRunner{}
c := &cobra.Command{ c := &cobra.Command{
Use: "cat DIR...", Use: "cat DIR",
Short: commands.CatShort, Short: commands.CatShort,
Long: commands.CatLong, Long: commands.CatLong,
Example: commands.CatExamples, Example: commands.CatExamples,
RunE: r.runE, RunE: r.runE,
Args: cobra.MaximumNArgs(1),
} }
fixDocs(name, c) fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
c.Flags().BoolVar(&r.Format, "format", true, c.Flags().BoolVar(&r.Format, "format", true,
"format resource config yaml before printing.") "format resource config yaml before printing.")
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false, c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
@@ -49,6 +50,8 @@ func GetCatRunner(name string) *CatRunner {
"if true, exclude non-local-config in the output.") "if true, exclude non-local-config in the output.")
c.Flags().StringVar(&r.OutputDest, "dest", "", c.Flags().StringVar(&r.OutputDest, "dest", "",
"if specified, write output to a file rather than stdout") "if specified, write output to a file rather than stdout")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"print resources recursively in all the nested subpackages")
r.Command = c r.Command = c
return r return r
} }
@@ -59,7 +62,6 @@ func CatCommand(name string) *cobra.Command {
// CatRunner contains the run function // CatRunner contains the run function
type CatRunner struct { type CatRunner struct {
IncludeSubpackages bool
Format bool Format bool
KeepAnnotations bool KeepAnnotations bool
WrapKind string WrapKind string
@@ -71,56 +73,102 @@ type CatRunner struct {
IncludeLocal bool IncludeLocal bool
ExcludeNonLocal bool ExcludeNonLocal bool
Command *cobra.Command Command *cobra.Command
RecurseSubPackages bool
} }
func (r *CatRunner) runE(c *cobra.Command, args []string) error { func (r *CatRunner) runE(c *cobra.Command, args []string) error {
// if there is a function-config specified, emit it var writer = c.OutOrStdout()
if r.OutputDest != "" {
o, err := os.Create(r.OutputDest)
if err != nil {
return errors.Wrap(err)
}
defer o.Close()
writer = o
}
if len(args) == 0 {
input := &kio.ByteReader{Reader: c.InOrStdin()}
// if there is a function-config specified, emit it
outputs, err := r.out(writer)
if err != nil {
return err
}
return handleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute())
}
e := executeCmdOnPkgs{
writer: writer,
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[0],
skipPkgPathPrint: true,
}
return e.execute()
}
func (r *CatRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
outputs, err := r.out(w)
if err != nil {
return err
}
err = kio.Pipeline{
Inputs: []kio.Reader{input},
Filters: r.catFilters(),
Outputs: outputs,
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s in package %q\n", err.Error(), pkgPath)
}
}
fmt.Fprintf(w, "---")
return nil
}
func (r *CatRunner) catFilters() []kio.Filter {
var fltrs []kio.Filter
// don't include reconcilers
fltrs = append(fltrs, &filters.IsLocalConfig{
IncludeLocalConfig: r.IncludeLocal,
ExcludeNonLocalConfig: r.ExcludeNonLocal,
})
if r.Format {
fltrs = append(fltrs, filters.FormatFilter{})
}
if r.StripComments {
fltrs = append(fltrs, filters.StripCommentsFilter{})
}
return fltrs
}
func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) {
var outputs []kio.Writer
var functionConfig *yaml.RNode var functionConfig *yaml.RNode
if r.FunctionConfig != "" { if r.FunctionConfig != "" {
configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig, configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig,
OmitReaderAnnotations: !r.KeepAnnotations}.Read() OmitReaderAnnotations: !r.KeepAnnotations}.Read()
if err != nil { if err != nil {
return err return outputs, err
} }
if len(configs) != 1 { if len(configs) != 1 {
return fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs)) return outputs, fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs))
} }
functionConfig = configs[0] functionConfig = configs[0]
} }
var inputs []kio.Reader
for _, a := range args {
inputs = append(inputs, kio.LocalPackageReader{
PackagePath: a,
IncludeSubpackages: r.IncludeSubpackages,
})
}
if len(inputs) == 0 {
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
}
var fltr []kio.Filter
// don't include reconcilers
fltr = append(fltr, &filters.IsLocalConfig{
IncludeLocalConfig: r.IncludeLocal,
ExcludeNonLocalConfig: r.ExcludeNonLocal,
})
if r.Format {
fltr = append(fltr, filters.FormatFilter{})
}
if r.StripComments {
fltr = append(fltr, filters.StripCommentsFilter{})
}
var out = c.OutOrStdout()
if r.OutputDest != "" {
o, err := os.Create(r.OutputDest)
if err != nil {
return handleError(c, errors.Wrap(err))
}
defer o.Close()
out = o
}
// remove this annotation explicitly, the ByteWriter won't clear it by // remove this annotation explicitly, the ByteWriter won't clear it by
// default because it doesn't set it // default because it doesn't set it
clear := []string{"config.kubernetes.io/path"} clear := []string{"config.kubernetes.io/path"}
@@ -128,9 +176,8 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
clear = nil clear = nil
} }
var outputs []kio.Writer
outputs = append(outputs, kio.ByteWriter{ outputs = append(outputs, kio.ByteWriter{
Writer: out, Writer: w,
KeepReaderAnnotations: r.KeepAnnotations, KeepReaderAnnotations: r.KeepAnnotations,
WrappingKind: r.WrapKind, WrappingKind: r.WrapKind,
WrappingAPIVersion: r.WrapApiVersion, WrappingAPIVersion: r.WrapApiVersion,
@@ -139,5 +186,5 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
ClearAnnotations: clear, ClearAnnotations: clear,
}) })
return handleError(c, kio.Pipeline{Inputs: inputs, Filters: fltr, Outputs: outputs}.Execute()) return outputs, nil
} }

View File

@@ -8,10 +8,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"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"
) )
// TODO(pwittrock): write tests for reading / writing ResourceLists // TODO(pwittrock): write tests for reading / writing ResourceLists
@@ -112,7 +115,7 @@ metadata:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3
`, b.String()) { ---`, b.String()) {
return return
} }
} }
@@ -168,8 +171,7 @@ metadata:
annotations: annotations:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3`), 0600)
`), 0600)
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
@@ -223,7 +225,7 @@ metadata:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3
`, b.String()) { ---`, b.String()) {
return return
} }
} }
@@ -305,7 +307,7 @@ metadata:
image: gcr.io/example/reconciler:v1 image: gcr.io/example/reconciler:v1
spec: spec:
replicas: 3 replicas: 3
`, b.String()) { ---`, b.String()) {
return return
} }
} }
@@ -362,8 +364,7 @@ metadata:
annotations: annotations:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3`), 0600)
`), 0600)
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
@@ -420,7 +421,7 @@ metadata:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3
`, string(actual)) { ---`, string(actual)) {
return return
} }
} }
@@ -477,8 +478,7 @@ metadata:
annotations: annotations:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3`), 0600)
`), 0600)
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
@@ -536,7 +536,132 @@ metadata:
app: nginx app: nginx
spec: spec:
replicas: 3 replicas: 3
`, string(actual)) { ---`, string(actual)) {
return return
} }
} }
func TestCatSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "cat-recurse-subpackages",
dataset: "dataset-without-setters",
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: myspace
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-deployment
namespace: myspace
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
{
name: "cat-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"-R=false"},
packagePath: "mysql",
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: myspace
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---`,
},
{
name: "cat-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"-R=false"},
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-deployment
namespace: myspace
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
}
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.GetCatRunner("")
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, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -5,7 +5,10 @@ package commands
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io"
"io/ioutil" "io/ioutil"
"path/filepath"
"strings" "strings"
"github.com/go-openapi/spec" "github.com/go-openapi/spec"
@@ -13,9 +16,7 @@ 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/setters" "sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -59,6 +60,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
@@ -78,7 +81,7 @@ type CreateSetterRunner struct {
} }
func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error { func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.set(c, args)) return handleError(c, r.createSetter(c, args))
} }
func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error { func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
@@ -111,42 +114,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
@@ -210,9 +177,20 @@ func (r *CreateSetterRunner) processSchema() error {
return nil return nil
} }
func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error { func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error {
if setterVersion == "v2" { if setterVersion == "v2" {
return r.CreateSetter.Create(r.OpenAPIFile, args[0]) e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.CreateSetter.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
} }
rw := &kio.LocalPackageReadWriter{PackagePath: args[0]} rw := &kio.LocalPackageReadWriter{PackagePath: args[0]}
@@ -226,6 +204,41 @@ func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
return nil return nil
} }
func (r *CreateSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
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(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.CreateSetter.Create()
if err != nil {
// return err if RecurseSubPackages is false
if !r.CreateSetter.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "created setter %q\n", r.CreateSetter.Name)
}
return nil
}
// schemaFromFile reads the contents from schemaPath and returns schema // schemaFromFile reads the contents from schemaPath and returns schema
func schemaFromFile(schemaPath string) (*spec.Schema, error) { func schemaFromFile(schemaPath string) (*spec.Schema, error) {
sc := &spec.Schema{} sc := &spec.Schema{}

View File

@@ -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"`,
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"`,
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"`,
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`,
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"`,
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`,
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"`,
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"`,
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"`,
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"`,
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.Contains(t, actualNormalized, expectedNormalized) {
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,92 @@ 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: `${baseDir}/mysql/
created setter "namespace"
${baseDir}/mysql/storage/
created setter "namespace"
`,
},
{
name: "create-setter-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
args: []string{"namespace", "myspace"},
expected: `${baseDir}/mysql/
created setter "namespace"
`,
},
{
name: "create-setter-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"namespace", "myspace"},
expected: `${baseDir}/mysql/storage/
created setter "namespace"
`,
},
{
name: "create-setter-already-exists",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"namespace", "myspace", "-R"},
expected: `${baseDir}/mysql/
setter with name "namespace" already exists, if you want to modify it, please delete the existing setter and recreate it
${baseDir}/mysql/nosetters/
created setter "namespace"
${baseDir}/mysql/storage/
setter with name "namespace" already exists, if you want to modify it, please delete the existing setter and recreate it
`,
},
}
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, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -5,13 +5,11 @@ package commands
import ( import (
"fmt" "fmt"
"io"
"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/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -19,10 +17,10 @@ import (
func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner { func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
r := &CreateSubstitutionRunner{} r := &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", "",
"name of the field to set -- e.g. --field image") "name of the field to set -- e.g. --field image")
@@ -30,6 +28,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 +49,52 @@ 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])) e := executeCmdOnPkgs{
} needOpenAPI: true,
writer: c.OutOrStdout(),
func (r *CreateSubstitutionRunner) preRunE(c *cobra.Command, args []string) error { rootPkgPath: args[0],
var err error recurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
r.CreateSubstitution.Name = args[1] cmdRunner: r,
}
err := e.execute()
if err != nil { if err != nil {
return err return handleError(c, err)
}
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.CreateSubstitution.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 %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) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
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(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.CreateSubstitution.Create()
if err != nil {
// return err if RecurseSubPackages is false
if !r.CreateSubstitution.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "created substitution %q\n", r.CreateSubstitution.Name)
}
return nil
}
func (r *CreateSubstitutionRunner) preRun(c *cobra.Command, args []string) {
r.CreateSubstitution.Name = args[1]
}

View File

@@ -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"`,
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"`,
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"`,
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.Contains(t, actualNormalized, expectedNormalized) {
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,89 @@ 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: `${baseDir}/mysql/
created substitution "image-tag"
${baseDir}/mysql/storage/
created substitution "image-tag"
`,
},
{
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: `${baseDir}/mysql/
created substitution "image-tag"`,
},
{
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: `${baseDir}/mysql/storage/
created substitution "image-tag"`,
},
{
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: `${baseDir}/mysql/
substitution with name "image-tag" already exists
${baseDir}/mysql/nosetters/
created substitution "image-tag"
${baseDir}/mysql/storage/
created substitution "image-tag"`,
},
}
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()
}
})
}
}

View File

@@ -4,11 +4,14 @@
package commands package commands
import ( import (
"fmt"
"io"
"path/filepath"
"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/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/fieldmeta" "sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -24,6 +27,8 @@ func NewDeleteSetterRunner(parent string) *DeleteSetterRunner {
PreRunE: r.preRunE, PreRunE: r.preRunE,
RunE: r.runE, RunE: r.runE,
} }
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"deletes setter recursively in all the nested subpackages")
fixDocs(parent, c) fixDocs(parent, c)
r.Command = c r.Command = c
@@ -35,9 +40,10 @@ func DeleteSetterCommand(parent string) *cobra.Command {
} }
type DeleteSetterRunner struct { type DeleteSetterRunner struct {
Command *cobra.Command Command *cobra.Command
DeleteSetter settersutil.DeleterCreator DeleteSetter settersutil.DeleterCreator
OpenAPIFile string OpenAPIFile string
RecurseSubPackages bool
} }
func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error { func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error {
@@ -50,17 +56,49 @@ func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error {
return err return err
} }
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
return err
}
return nil return nil
} }
func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error { func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.delete(c, args)) e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
} }
func (r *DeleteSetterRunner) delete(c *cobra.Command, args []string) error { func (r *DeleteSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
return r.DeleteSetter.Delete(r.OpenAPIFile, args[0]) openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.DeleteSetter = settersutil.DeleterCreator{
Name: r.DeleteSetter.Name,
DefinitionPrefix: fieldmeta.SetterDefinitionPrefix,
RecurseSubPackages: r.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.DeleteSetter.Delete()
if err != nil {
// return err if RecurseSubPackages is false
if !r.DeleteSetter.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "deleted setter %q\n", r.DeleteSetter.Name)
}
return nil
} }

View File

@@ -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"
) )
@@ -52,6 +53,7 @@ openAPI:
value: "3" value: "3"
setBy: me setBy: me
`, `,
out: `deleted setter "replicas-setter"`,
expectedOpenAPI: ` expectedOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -95,6 +97,7 @@ openAPI:
name: image name: image
value: nginx value: nginx
`, `,
out: `deleted setter "replicas-setter"`,
expectedOpenAPI: ` expectedOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -158,6 +161,7 @@ spec:
- "b" - "b"
- "c" - "c"
`, `,
out: `deleted setter "list"`,
expectedResources: ` expectedResources: `
apiVersion: example.com/v1beta1 apiVersion: example.com/v1beta1
kind: Example1 kind: Example1
@@ -226,7 +230,7 @@ metadata:
spec: spec:
replicas: 3 # {"$openapi" : "replicas-setter"} replicas: 3 # {"$openapi" : "replicas-setter"}
`, `,
err: `setter with name image does not exist`, err: `setter "image" does not exist`,
}, },
{ {
name: "delete setter used in substitution error", name: "delete setter used in substitution error",
@@ -287,7 +291,7 @@ openAPI:
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
`, `,
err: `setter is used in substitution image, please delete the parent substitution first`, err: `setter "image-name" is used in substitution "image", please delete the parent substitution first`,
}, },
} }
for i := range tests { for i := range tests {
@@ -297,24 +301,18 @@ kind: Deployment
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)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600) 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 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()
} }
@@ -327,21 +325,29 @@ kind: Deployment
runner := commands.NewDeleteSetterRunner("") runner := commands.NewDeleteSetterRunner("")
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) {
t.FailNow() t.FailNow()
} else {
assert.Equal(t, err.Error(), test.err)
return
} }
assert.Equal(t, test.err, err.Error())
return
} }
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
t.FailNow() t.FailNow()
} }
if !assert.Equal(t, test.out, out.String()) { // normalize path format for windows
actualNorm := strings.Replace(
strings.Replace(out.String(), "\\", "/", -1),
"//", "/", -1)
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expectedOut, "\\", "/", -1)
if !assert.Contains(t, strings.TrimSpace(actualNorm), expectedNormalized) {
t.FailNow() t.FailNow()
} }
@@ -355,7 +361,7 @@ kind: Deployment
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()
} }
@@ -367,3 +373,80 @@ kind: Deployment
}) })
} }
} }
func TestDeleteSetterSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "delete-setter-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"namespace", "-R"},
expected: `${baseDir}/mysql/
deleted setter "namespace"
${baseDir}/mysql/nosetters/
setter "namespace" does not exist
${baseDir}/mysql/storage/
deleted setter "namespace"
`,
},
{
name: "delete-setter-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"namespace"},
expected: `${baseDir}/mysql/
deleted setter "namespace"
`,
},
{
name: "delete-setter-nested-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql/storage",
args: []string{"namespace"},
expected: `${baseDir}/mysql/storage/
deleted setter "namespace"
`,
},
}
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.NewDeleteSetterRunner("")
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, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -4,10 +4,13 @@
package commands package commands
import ( import (
"fmt"
"io"
"path/filepath"
"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/fieldmeta" "sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -20,6 +23,8 @@ func NewDeleteSubstitutionRunner(parent string) *DeleteSubstitutionRunner {
PreRunE: r.preRunE, PreRunE: r.preRunE,
RunE: r.runE, RunE: r.runE,
} }
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"deletes substitution recursively in all the nested subpackages")
fixDocs(parent, c) fixDocs(parent, c)
r.Command = c r.Command = c
@@ -34,6 +39,7 @@ type DeleteSubstitutionRunner struct {
Command *cobra.Command Command *cobra.Command
DeleteSubstitution settersutil.DeleterCreator DeleteSubstitution settersutil.DeleterCreator
OpenAPIFile string OpenAPIFile string
RecurseSubPackages bool
} }
func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) error { func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) error {
@@ -46,17 +52,49 @@ func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) erro
return err return err
} }
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
return err
}
return nil return nil
} }
func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error { func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.delete(c, args)) e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
} }
func (r *DeleteSubstitutionRunner) delete(c *cobra.Command, args []string) error { func (r *DeleteSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error {
return r.DeleteSubstitution.Delete(r.OpenAPIFile, args[0]) openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.DeleteSubstitution = settersutil.DeleterCreator{
Name: r.DeleteSubstitution.Name,
DefinitionPrefix: fieldmeta.SubstitutionDefinitionPrefix,
RecurseSubPackages: r.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.DeleteSubstitution.Delete()
if err != nil {
// return err if RecurseSubPackages is false
if !r.DeleteSubstitution.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "deleted substitution %q\n", r.DeleteSubstitution.Name)
}
return nil
} }

View File

@@ -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"
) )
@@ -79,6 +80,7 @@ spec:
- name: sidecar - name: sidecar
image: nginx:1.7.9 # {"$ref":"#/definitions/io.k8s.cli.substitutions.my.image"} image: nginx:1.7.9 # {"$ref":"#/definitions/io.k8s.cli.substitutions.my.image"}
`, `,
out: `deleted substitution "my.image"`,
expectedResources: ` expectedResources: `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@@ -169,6 +171,7 @@ spec:
- name: sidecar - name: sidecar
image: nginx:1.7.9 # {"$openapi":"my-image-sub"} image: nginx:1.7.9 # {"$openapi":"my-image-sub"}
`, `,
out: `deleted substitution "my-image-sub"`,
expectedResources: ` expectedResources: `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@@ -297,7 +300,7 @@ openAPI:
value: "3" value: "3"
setBy: me setBy: me
`, `,
err: "substitution with name my-image-sub-not-present does not exist", err: `substitution "my-image-sub-not-present" does not exist`,
}, },
{ {
@@ -415,7 +418,7 @@ spec:
- name: sidecar - name: sidecar
image: nginx::1.7.9 # {"$openapi":"my-image-subst"} image: nginx::1.7.9 # {"$openapi":"my-image-subst"}
`, `,
err: "substitution is used in substitution my-nested-subst, please delete the parent substitution first", err: `substitution "my-image-subst" is used in substitution "my-nested-subst", please delete the parent substitution first`,
}, },
} }
for i := range tests { for i := range tests {
@@ -425,24 +428,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)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600) 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 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()
} }
@@ -455,21 +452,38 @@ spec:
runner := commands.NewDeleteSubstitutionRunner("") runner := commands.NewDeleteSubstitutionRunner("")
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) {
t.FailNow() t.FailNow()
} else {
assert.Equal(t, err.Error(), test.err)
return
} }
assert.Equal(t, test.err, err.Error())
return
} }
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
t.FailNow() t.FailNow()
} }
if !assert.Equal(t, test.out, out.String()) { // normalize path format for windows
actualNorm := strings.Replace(
strings.Replace(out.String(), "\\", "/", -1),
"//", "/", -1)
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
expectedNorm := strings.Replace(expectedOut, "\\", "/", -1)
if !assert.Contains(t, strings.TrimSpace(actualNorm), expectedNorm) {
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t,
strings.TrimSpace(test.expectedOpenAPI),
strings.TrimSpace(string(actualOpenAPI))) {
t.FailNow() t.FailNow()
} }
@@ -480,16 +494,74 @@ spec:
if !assert.Equal(t, if !assert.Equal(t,
strings.TrimSpace(test.expectedResources), strings.TrimSpace(test.expectedResources),
strings.TrimSpace(string(actualResources))) { strings.TrimSpace(string(actualResources))) {
return t.FailNow()
} }
})
actualOpenAPI, err := ioutil.ReadFile(f.Name()) }
if !assert.NoError(t, err) { }
t.FailNow()
} func TestDeleteSubstitutionSubPackages(t *testing.T) {
if !assert.Equal(t, var tests = []struct {
strings.TrimSpace(test.expectedOpenAPI), name string
strings.TrimSpace(string(actualOpenAPI))) { dataset string
packagePath string
args []string
expected string
}{
{
name: "delete-substitution-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"image-tag", "-R"},
expected: `${baseDir}/mysql/
deleted substitution "image-tag"
${baseDir}/mysql/nosetters/
substitution "image-tag" does not exist
${baseDir}/mysql/storage/
substitution "image-tag" does not exist
`,
},
{
name: "delete-setter-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"image-tag"},
expected: `${baseDir}/mysql/
deleted substitution "image-tag"
`,
},
}
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.NewDeleteSubstitutionRunner("")
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, expectedNormalized, actualNormalized) {
t.FailNow() t.FailNow()
} }
}) })

View File

@@ -7,15 +7,14 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"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/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/fieldmeta" "sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters" "sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2" "sigs.k8s.io/kustomize/kyaml/setters2"
) )
@@ -36,6 +35,8 @@ func NewListSettersRunner(parent string) *ListSettersRunner {
"output as github markdown") "output as github markdown")
c.Flags().BoolVar(&r.IncludeSubst, "include-subst", false, c.Flags().BoolVar(&r.IncludeSubst, "include-subst", false,
"include substitutions in the output") "include substitutions in the output")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"list setters recursively in all the nested subpackages")
fixDocs(parent, c) fixDocs(parent, c)
r.Command = c r.Command = c
return r return r
@@ -46,11 +47,12 @@ func ListSettersCommand(parent string) *cobra.Command {
} }
type ListSettersRunner struct { type ListSettersRunner struct {
Command *cobra.Command Command *cobra.Command
Lookup setters.LookupSetters Lookup setters.LookupSetters
List setters2.List List setters2.List
Markdown bool Markdown bool
IncludeSubst bool IncludeSubst bool
RecurseSubPackages bool
} }
func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error { func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
@@ -65,48 +67,50 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error { func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" { if setterVersion == "v2" {
openAPIFileName, err := ext.OpenAPIFileName() e := executeCmdOnPkgs{
if err != nil { needOpenAPI: true,
return err writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
} }
openAPIPaths, err := pathutil.SubDirsWithFile(args[0], openAPIFileName) err := e.execute()
if err != nil { if err != nil {
return err return handleError(c, err)
}
if len(openAPIPaths) == 0 {
return errors.Errorf("unable to find %s in %s", openAPIFileName, args[0])
}
// list setters for all the subpackages with openAPI file paths
for _, openAPIPath := range openAPIPaths {
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
resourcePath := strings.TrimSuffix(openAPIPath, openAPIFileName)
fmt.Fprintf(c.OutOrStdout(), "%s\n", resourcePath)
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(c, openAPIPath); err != nil {
return err
}
}
} }
return nil return nil
} }
return handleError(c, lookup(r.Lookup, c, args)) return handleError(c, lookup(r.Lookup, c, args))
} }
func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourcePath string) error { func (r *ListSettersRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
openAPIPath := filepath.Join(pkgPath, openAPIFileName)
if err := r.ListSetters(w, openAPIPath, pkgPath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(w, openAPIPath); err != nil {
return err
}
}
return nil
}
func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath string) error {
// use setters v2 // use setters v2
if err := r.List.ListSetters(openAPIPath, resourcePath); err != nil { if err := r.List.ListSetters(openAPIPath, resourcePath); err != nil {
return err return err
} }
table := newTable(c.OutOrStdout(), r.Markdown) table := newTable(w, r.Markdown)
table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED"}) table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED"})
for i := range r.List.Setters { for i := range r.List.Setters {
s := r.List.Setters[i] s := r.List.Setters[i]
@@ -137,12 +141,12 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourceP
return nil return nil
} }
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, openAPIPath string) error { func (r *ListSettersRunner) ListSubstitutions(w io.Writer, openAPIPath string) error {
// use setters v2 // use setters v2
if err := r.List.ListSubst(openAPIPath); err != nil { if err := r.List.ListSubst(openAPIPath); err != nil {
return err return err
} }
table := newTable(c.OutOrStdout(), r.Markdown) table := newTable(w, r.Markdown)
b := tablewriter.Border{Top: true} b := tablewriter.Border{Top: true}
table.SetBorders(b) table.SetBorders(b)

View File

@@ -471,9 +471,11 @@ 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,11 +483,26 @@ 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
`,
},
{
name: "list-replicas",
dataset: "dataset-with-setters/mysql",
args: []string{"--recurse-subpackages=false"},
expected: `
test/testdata/dataset-with-setters/mysql/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image mysql 1 No
namespace myspace 1 No
tag 1.7.9 1 No
`, `,
}, },
} }
@@ -509,7 +526,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()
} }
}) })

View File

@@ -5,7 +5,9 @@ package commands
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"path/filepath"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -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,23 @@ 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]) e := executeCmdOnPkgs{
fmt.Fprintf(c.OutOrStdout(), "set %d fields\n", count) needOpenAPI: true,
return handleError(c, err) writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.Set.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
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))
@@ -142,6 +154,38 @@ func (r *SetRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, lookup(r.Lookup, c, args)) return handleError(c, lookup(r.Lookup, c, args))
} }
func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
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(pkgPath, openAPIFileName),
OpenAPIFileName: openAPIFileName,
ResourcesPath: pkgPath,
RecurseSubPackages: r.Set.RecurseSubPackages,
}
count, err := r.Set.Set()
if err != nil {
// return err if RecurseSubPackages is false
if !r.Set.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "set %d field(s)\n", count)
}
return nil
}
func lookup(l setters.LookupSetters, c *cobra.Command, args []string) error { func lookup(l setters.LookupSetters, c *cobra.Command, args []string) error {
// lookup the setters // lookup the setters
err := kio.Pipeline{ err := kio.Pipeline{

View File

@@ -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"
) )
@@ -30,7 +31,7 @@ func TestSetCommand(t *testing.T) {
{ {
name: "set replicas", name: "set replicas",
args: []string{"replicas", "4", "--description", "hi there", "--set-by", "pw"}, args: []string{"replicas", "4", "--description", "hi there", "--set-by", "pw"},
out: "set 1 fields\n", out: "set 1 field(s)\n",
inputOpenAPI: ` inputOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -126,7 +127,7 @@ spec:
{ {
name: "set replicas no description", name: "set replicas no description",
args: []string{"replicas", "4"}, args: []string{"replicas", "4"},
out: "set 1 fields\n", out: "set 1 field(s)\n",
inputOpenAPI: ` inputOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -174,7 +175,7 @@ spec:
{ {
name: "set image with value", name: "set image with value",
args: []string{"tag", "1.8.1"}, args: []string{"tag", "1.8.1"},
out: "set 1 fields\n", out: "set 1 field(s)\n",
inputOpenAPI: ` inputOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -509,7 +510,7 @@ list in body should have at most 2 items`,
{ {
name: "set replicas with value set by flag", name: "set replicas with value set by flag",
args: []string{"replicas", "--values", "4", "--description", "hi there"}, args: []string{"replicas", "--values", "4", "--description", "hi there"},
out: "set 1 fields\n", out: "set 1 field(s)\n",
inputOpenAPI: ` inputOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -605,7 +606,7 @@ spec:
{ {
name: "openAPI list values set by flag success", name: "openAPI list values set by flag success",
args: []string{"list", "--values", "10", "--values", "11"}, args: []string{"list", "--values", "10", "--values", "11"},
out: "set 1 fields\n", out: "set 1 field(s)\n",
inputOpenAPI: ` inputOpenAPI: `
kind: Kptfile kind: Kptfile
openAPI: openAPI:
@@ -709,7 +710,7 @@ list in body should have at most 2 items`,
{ {
name: "nested substitution", name: "nested substitution",
args: []string{"my-image-setter", "ubuntu"}, args: []string{"my-image-setter", "ubuntu"},
out: "set 2 fields\n", out: "set 2 field(s)\n",
inputOpenAPI: ` inputOpenAPI: `
apiVersion: v1alpha1 apiVersion: v1alpha1
kind: Example kind: Example
@@ -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,82 @@ 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: `${baseDir}/mysql/
set 1 field(s)
${baseDir}/mysql/nosetters/
setter "namespace" is not found
${baseDir}/mysql/storage/
set 1 field(s)
`,
},
{
name: "set-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"namespace", "otherspace"},
expected: `${baseDir}/mysql/
set 1 field(s)
`,
},
{
name: "set-nested-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql/storage",
args: []string{"namespace", "otherspace"},
expected: `${baseDir}/mysql/storage/
set 1 field(s)
`,
},
}
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()
}
})
}
}

View File

@@ -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'

View File

@@ -5,9 +5,11 @@ package commands
import ( import (
"fmt" "fmt"
"io"
"sort" "sort"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"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/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/sets" "sigs.k8s.io/kustomize/kyaml/sets"
@@ -17,18 +19,18 @@ import (
func GetCountRunner(name string) *CountRunner { func GetCountRunner(name string) *CountRunner {
r := &CountRunner{} r := &CountRunner{}
c := &cobra.Command{ c := &cobra.Command{
Use: "count DIR...", Use: "count [DIR]",
Args: cobra.MaximumNArgs(1),
Short: commands.CountShort, Short: commands.CountShort,
Long: commands.CountLong, Long: commands.CountLong,
Example: commands.CountExamples, Example: commands.CountExamples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(name, c) fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
c.Flags().BoolVar(&r.Kind, "kind", true, c.Flags().BoolVar(&r.Kind, "kind", true,
"count resources by kind.") "count resources by kind.")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"prints count of resources recursively in all the nested subpackages")
r.Command = c r.Command = c
return r return r
} }
@@ -42,20 +44,56 @@ type CountRunner struct {
IncludeSubpackages bool IncludeSubpackages bool
Kind bool Kind bool
Command *cobra.Command Command *cobra.Command
RecurseSubPackages bool
} }
func (r *CountRunner) runE(c *cobra.Command, args []string) error { func (r *CountRunner) runE(c *cobra.Command, args []string) error {
var inputs []kio.Reader if len(args) == 0 {
for _, a := range args { input := &kio.ByteReader{Reader: c.InOrStdin()}
inputs = append(inputs, kio.LocalPackageReader{
PackagePath: a, return handleError(c, kio.Pipeline{
IncludeSubpackages: r.IncludeSubpackages, Inputs: []kio.Reader{input},
}) Outputs: r.out(c.OutOrStdout()),
} }.Execute())
if len(inputs) == 0 {
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
} }
e := executeCmdOnPkgs{
writer: c.OutOrStdout(),
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[0],
}
return e.execute()
}
func (r *CountRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{input},
Outputs: r.out(w),
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s\n", err.Error())
}
}
return nil
}
func (r *CountRunner) out(w io.Writer) []kio.Writer {
var out []kio.Writer var out []kio.Writer
if r.Kind { if r.Kind {
out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error { out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error {
@@ -69,20 +107,15 @@ func (r *CountRunner) runE(c *cobra.Command, args []string) error {
order := k.List() order := k.List()
sort.Strings(order) sort.Strings(order)
for _, k := range order { for _, k := range order {
fmt.Fprintf(c.OutOrStdout(), "%s: %d\n", k, count[k]) fmt.Fprintf(w, "%s: %d\n", k, count[k])
} }
return nil return nil
})) }))
} else { } else {
out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error { out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error {
fmt.Fprintf(c.OutOrStdout(), "%d\n", len(nodes)) fmt.Fprintf(w, "%d\n", len(nodes))
return nil return nil
})) }))
} }
return handleError(c, kio.Pipeline{ return out
Inputs: inputs,
Outputs: out,
}.Execute())
} }

View File

@@ -8,10 +8,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"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"
) )
func TestCountCommand_files(t *testing.T) { func TestCountCommand_files(t *testing.T) {
@@ -67,7 +70,80 @@ spec:
return return
} }
if !assert.Equal(t, "Deployment: 2\nService: 1\n", b.String()) { if !assert.Contains(t, b.String(), "Deployment: 2\nService: 1\n") {
return return
} }
} }
func TestCountSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "count-recurse-subpackages",
dataset: "dataset-without-setters",
expected: `${baseDir}/mysql/
Deployment: 1
${baseDir}/mysql/storage/
Deployment: 1
`,
},
{
name: "count-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"-R=false"},
packagePath: "mysql",
expected: `${baseDir}/mysql/
Deployment: 1
`,
},
{
name: "count-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"-R=false"},
expected: `${baseDir}/mysql/storage/
Deployment: 1
`,
},
}
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.GetCountRunner("")
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, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -4,7 +4,11 @@
package commands package commands
import ( import (
"fmt"
"io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"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/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -33,6 +37,8 @@ formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace'
`if true, override existing filepath annotations.`) `if true, override existing filepath annotations.`)
c.Flags().BoolVar(&r.UseSchema, "use-schema", false, c.Flags().BoolVar(&r.UseSchema, "use-schema", false,
`if true, uses openapi resource schema to format resources.`) `if true, uses openapi resource schema to format resources.`)
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"formats resource files recursively in all the nested subpackages")
r.Command = c r.Command = c
return r return r
} }
@@ -43,12 +49,13 @@ func FmtCommand(name string) *cobra.Command {
// FmtRunner contains the run function // FmtRunner contains the run function
type FmtRunner struct { type FmtRunner struct {
Command *cobra.Command Command *cobra.Command
FilenamePattern string FilenamePattern string
SetFilenames bool SetFilenames bool
KeepAnnotations bool KeepAnnotations bool
Override bool Override bool
UseSchema bool UseSchema bool
RecurseSubPackages bool
} }
func (r *FmtRunner) preRunE(c *cobra.Command, args []string) error { func (r *FmtRunner) preRunE(c *cobra.Command, args []string) error {
@@ -59,17 +66,6 @@ func (r *FmtRunner) preRunE(c *cobra.Command, args []string) error {
} }
func (r *FmtRunner) runE(c *cobra.Command, args []string) error { func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
f := []kio.Filter{filters.FormatFilter{
UseSchema: r.UseSchema,
}}
// format with file names
if r.SetFilenames {
f = append(f, &filters.FileSetter{
FilenamePattern: r.FilenamePattern,
Override: r.Override,
})
}
// format stdin if there are no args // format stdin if there are no args
if len(args) == 0 { if len(args) == 0 {
@@ -79,20 +75,64 @@ func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
KeepReaderAnnotations: r.KeepAnnotations, KeepReaderAnnotations: r.KeepAnnotations,
} }
return handleError(c, kio.Pipeline{ return handleError(c, kio.Pipeline{
Inputs: []kio.Reader{rw}, Filters: f, Outputs: []kio.Writer{rw}}.Execute()) Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute())
} }
for i := range args { for _, rootPkgPath := range args {
path := args[i] e := executeCmdOnPkgs{
rw := &kio.LocalPackageReadWriter{ writer: c.OutOrStdout(),
NoDeleteFiles: true, needOpenAPI: false,
PackagePath: path, recurseSubPackages: r.RecurseSubPackages,
KeepReaderAnnotations: r.KeepAnnotations} cmdRunner: r,
err := kio.Pipeline{ rootPkgPath: rootPkgPath,
Inputs: []kio.Reader{rw}, Filters: f, Outputs: []kio.Writer{rw}}.Execute() }
err := e.execute()
if err != nil { if err != nil {
return handleError(c, err) return err
} }
} }
return nil return nil
} }
func (r *FmtRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
rw := &kio.LocalPackageReadWriter{
NoDeleteFiles: true,
PackagePath: pkgPath,
KeepReaderAnnotations: r.KeepAnnotations, PackageFileName: openAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute()
if err != nil {
// return err if RecurseSubPackages is false
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprint(w, "formatted resource files in the package\n")
}
return nil
}
func (r *FmtRunner) fmtFilters() []kio.Filter {
fmtFilters := []kio.Filter{filters.FormatFilter{
UseSchema: r.UseSchema,
}}
// format with file names
if r.SetFilenames {
fmtFilters = append(fmtFilters, &filters.FileSetter{
FilenamePattern: r.FilenamePattern,
Override: r.Override,
})
}
return fmtFilters
}

View File

@@ -7,12 +7,15 @@ 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/internal/commands" "sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/kio/filters/testyaml" "sigs.k8s.io/kustomize/kyaml/kio/filters/testyaml"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/testutil" "sigs.k8s.io/kustomize/kyaml/testutil"
) )
@@ -163,3 +166,78 @@ func TestCmd_failFileContents(t *testing.T) {
// expect an error // expect an error
assert.EqualError(t, err, "yaml: line 1: did not find expected node content") assert.EqualError(t, err, "yaml: line 1: did not find expected node content")
} }
func TestFmtSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "fmt-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"-R"},
expected: `${baseDir}/mysql/
formatted resource files in the package
${baseDir}/mysql/nosetters/
formatted resource files in the package
${baseDir}/mysql/storage/
formatted resource files in the package
`,
},
{
name: "fmt-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
expected: `${baseDir}/mysql/
formatted resource files in the package
`,
},
{
name: "fmt-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
expected: `${baseDir}/mysql/storage/
formatted resource files in the package
`,
},
}
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.GetFmtRunner("")
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()
}
})
}
}

View File

@@ -5,10 +5,12 @@ package commands
import ( import (
"fmt" "fmt"
"io"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"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/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -18,22 +20,21 @@ import (
func GetGrepRunner(name string) *GrepRunner { func GetGrepRunner(name string) *GrepRunner {
r := &GrepRunner{} r := &GrepRunner{}
c := &cobra.Command{ c := &cobra.Command{
Use: "grep QUERY [DIR]...", Use: "grep QUERY [DIR]",
Short: commands.GrepShort, Short: commands.GrepShort,
Long: commands.GrepLong, Long: commands.GrepLong,
Example: commands.GrepExamples, Example: commands.GrepExamples,
PreRunE: r.preRunE, PreRunE: r.preRunE,
RunE: r.runE, RunE: r.runE,
Args: cobra.MinimumNArgs(1), Args: cobra.MaximumNArgs(2),
} }
fixDocs(name, c) fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true, c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true,
"annotate resources with their file origins.") "annotate resources with their file origins.")
c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "", false, c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "", false,
"Selected Resources are those not matching any of the specified patterns..") "Selected Resources are those not matching any of the specified patterns..")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"also print resources recursively in all the nested subpackages")
r.Command = c r.Command = c
return r return r
} }
@@ -44,11 +45,11 @@ func GrepCommand(name string) *cobra.Command {
// GrepRunner contains the run function // GrepRunner contains the run function
type GrepRunner struct { type GrepRunner struct {
IncludeSubpackages bool KeepAnnotations bool
KeepAnnotations bool Command *cobra.Command
Command *cobra.Command
filters.GrepFilter filters.GrepFilter
Format bool Format bool
RecurseSubPackages bool
} }
func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error { func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
@@ -101,25 +102,57 @@ func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
} }
func (r *GrepRunner) runE(c *cobra.Command, args []string) error { func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
var filters = []kio.Filter{r.GrepFilter} if len(args) == 1 {
input := &kio.ByteReader{Reader: c.InOrStdin()}
var inputs []kio.Reader return handleError(c, kio.Pipeline{
for _, a := range args[1:] { Inputs: []kio.Reader{input},
inputs = append(inputs, kio.LocalPackageReader{ Filters: []kio.Filter{r.GrepFilter},
PackagePath: a, Outputs: []kio.Writer{kio.ByteWriter{
IncludeSubpackages: r.IncludeSubpackages, Writer: c.OutOrStdout(),
}) KeepReaderAnnotations: r.KeepAnnotations,
} }},
if len(inputs) == 0 { }.Execute())
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
} }
return handleError(c, kio.Pipeline{ e := executeCmdOnPkgs{
Inputs: inputs, writer: c.OutOrStdout(),
Filters: filters, needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[1],
skipPkgPathPrint: true,
}
return e.execute()
}
func (r *GrepRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{input},
Filters: []kio.Filter{r.GrepFilter},
Outputs: []kio.Writer{kio.ByteWriter{ Outputs: []kio.Writer{kio.ByteWriter{
Writer: c.OutOrStdout(), Writer: w,
KeepReaderAnnotations: r.KeepAnnotations, KeepReaderAnnotations: r.KeepAnnotations,
}}, }},
}.Execute()) }.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s\n", err.Error())
}
}
fmt.Fprintf(w, "---")
return nil
} }

View File

@@ -8,10 +8,12 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/internal/commands" "sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
) )
// TestGrepCommand_files verifies grep reads the files and filters them // TestGrepCommand_files verifies grep reads the files and filters them
@@ -68,7 +70,7 @@ spec:
return return
} }
if !assert.Equal(t, `kind: Deployment if !assert.Contains(t, b.String(), `kind: Deployment
metadata: metadata:
labels: labels:
app: nginx2 app: nginx2
@@ -90,7 +92,7 @@ metadata:
spec: spec:
selector: selector:
app: nginx app: nginx
`, b.String()) { `) {
return return
} }
} }
@@ -136,7 +138,7 @@ spec:
return return
} }
if !assert.Equal(t, `kind: Deployment if !assert.Contains(t, b.String(), `kind: Deployment
metadata: metadata:
labels: labels:
app: nginx2 app: nginx2
@@ -156,7 +158,7 @@ metadata:
spec: spec:
selector: selector:
app: nginx app: nginx
`, b.String()) { `) {
return return
} }
} }
@@ -250,7 +252,7 @@ spec:
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
if !assert.Equal(t, `kind: Deployment if !assert.Contains(t, b.String(), `kind: Deployment
metadata: metadata:
labels: labels:
app: nginx1.7 app: nginx1.7
@@ -264,7 +266,142 @@ spec:
containers: containers:
- name: nginx - name: nginx
image: nginx:1.7.9 image: nginx:1.7.9
`, b.String()) { `) {
return return
} }
} }
func TestGrepSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "grep-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"kind=Deployment"},
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: mysql-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: storage-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
{
name: "grep-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"kind=Deployment", "-R=false"},
packagePath: "mysql",
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: mysql-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---`,
},
{
name: "grep-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"kind=Deployment", "-R=false"},
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: storage-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
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.GetGrepRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append(test.args, filepath.Join(baseDir, test.packagePath)))
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, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -9,11 +9,13 @@ import (
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"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/fn/runtime/runtimeutil" "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
"sigs.k8s.io/kustomize/kyaml/runfn" "sigs.k8s.io/kustomize/kyaml/runfn"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
) )
// GetCatRunner returns a RunFnRunner. // GetCatRunner returns a RunFnRunner.
@@ -65,6 +67,11 @@ func GetRunFnRunner(name string) *RunFnRunner {
r.Command.Flags().StringArrayVar( r.Command.Flags().StringArrayVar(
&r.Mounts, "mount", []string{}, &r.Mounts, "mount", []string{},
"a list of storage options read from the filesystem") "a list of storage options read from the filesystem")
r.Command.Flags().BoolVar(
&r.LogSteps, "log-steps", false, "log steps to stderr")
r.Command.Flags().StringArrayVarP(
&r.Env, "env", "e", []string{},
"a list of environment variables to be used by functions")
return r return r
} }
@@ -91,6 +98,8 @@ type RunFnRunner struct {
Network bool Network bool
NetworkName string NetworkName string
Mounts []string Mounts []string
LogSteps bool
Env []string
} }
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error { func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
@@ -99,7 +108,7 @@ func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
// getContainerFunctions parses the commandline flags and arguments into explicit // getContainerFunctions parses the commandline flags and arguments into explicit
// Functions to run. // Functions to run.
func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, args, dataItems []string) ( func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, dataItems []string) (
[]*yaml.RNode, error) { []*yaml.RNode, error) {
if r.Image == "" && r.StarPath == "" && r.ExecPath == "" && r.StarURL == "" { if r.Image == "" && r.StarPath == "" && r.ExecPath == "" && r.StarURL == "" {
@@ -193,7 +202,7 @@ data: {}
} }
err = rc.PipeE( err = rc.PipeE(
yaml.LookupCreate(yaml.MappingNode, "metadata", "annotations"), yaml.LookupCreate(yaml.MappingNode, "metadata", "annotations"),
yaml.SetField("config.kubernetes.io/function", yaml.NewScalarRNode(value))) yaml.SetField(runtimeutil.FunctionAnnotationKey, yaml.NewScalarRNode(value)))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -267,7 +276,7 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
return errors.Errorf("0 or 1 arguments supported, function arguments go after '--'") return errors.Errorf("0 or 1 arguments supported, function arguments go after '--'")
} }
fns, err := r.getContainerFunctions(c, args, dataItems) fns, err := r.getContainerFunctions(c, dataItems)
if err != nil { if err != nil {
return err return err
} }
@@ -305,6 +314,8 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
EnableExec: r.EnableExec, EnableExec: r.EnableExec,
StorageMounts: storageMounts, StorageMounts: storageMounts,
ResultsDir: r.ResultsDir, ResultsDir: r.ResultsDir,
LogSteps: r.LogSteps,
Env: r.Env,
} }
// don't consider args for the function // don't consider args for the function

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/runfn" "sigs.k8s.io/kustomize/kyaml/runfn"
) )
@@ -203,6 +204,7 @@ apiVersion: v1
Path: "dir", Path: "dir",
NetworkName: "bridge", NetworkName: "bridge",
EnableStarlark: true, EnableStarlark: true,
Env: []string{},
}, },
}, },
{ {
@@ -256,6 +258,7 @@ apiVersion: v1
Path: "dir", Path: "dir",
NetworkName: "bridge", NetworkName: "bridge",
ResultsDir: "foo/", ResultsDir: "foo/",
Env: []string{},
}, },
expected: ` expected: `
metadata: metadata:
@@ -283,6 +286,27 @@ apiVersion: v1
args: []string{"run", "dir", "--image", "foo:bar", "--", "a=b", "c", "e=f"}, args: []string{"run", "dir", "--image", "foo:bar", "--", "a=b", "c", "e=f"},
err: "must have keys and values separated by", err: "must have keys and values separated by",
}, },
{
name: "log steps",
args: []string{"run", "dir", "--log-steps"},
path: "dir",
expectedStruct: &runfn.RunFns{
Path: "dir",
NetworkName: "bridge",
LogSteps: true,
Env: []string{},
},
},
{
name: "envs",
args: []string{"run", "dir", "--env", "FOO=BAR", "-e", "BAR"},
path: "dir",
expectedStruct: &runfn.RunFns{
Path: "dir",
NetworkName: "bridge",
Env: []string{"FOO=BAR", "BAR"},
},
},
} }
for i := range tests { for i := range tests {
@@ -385,5 +409,4 @@ apiVersion: v1
}) })
} }
} }

View File

@@ -0,0 +1,6 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: mysql
packageMetadata:
shortDescription: sample description

View 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

View File

@@ -0,0 +1,6 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: storage
packageMetadata:
shortDescription: sample description

View 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

View File

@@ -7,6 +7,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"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/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -26,8 +27,6 @@ func GetTreeRunner(name string) *TreeRunner {
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
} }
fixDocs(name, c) fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
// TODO(pwittrock): Figure out if these are the right things to expose, and consider making it // TODO(pwittrock): Figure out if these are the right things to expose, and consider making it
// a list of options instead of individual flags // a list of options instead of individual flags
@@ -59,29 +58,33 @@ func TreeCommand(name string) *cobra.Command {
// TreeRunner contains the run function // TreeRunner contains the run function
type TreeRunner struct { type TreeRunner struct {
IncludeSubpackages bool Command *cobra.Command
Command *cobra.Command name bool
name bool resources bool
resources bool ports bool
ports bool images bool
images bool replicas bool
replicas bool all bool
all bool env bool
env bool args bool
args bool cmd bool
cmd bool fields []string
fields []string includeLocal bool
includeLocal bool excludeNonLocal bool
excludeNonLocal bool structure string
structure string
} }
func (r *TreeRunner) runE(c *cobra.Command, args []string) error { func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
var input kio.Reader var input kio.Reader
var root = "." var root = "."
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
matchFilesGlob := append([]string{openAPIFileName}, kio.DefaultMatch...)
if len(args) == 1 { if len(args) == 1 {
root = filepath.Clean(args[0]) root = filepath.Clean(args[0])
input = kio.LocalPackageReader{PackagePath: args[0]} input = kio.LocalPackageReader{PackagePath: args[0], MatchFilesGlob: matchFilesGlob}
} else { } else {
input = &kio.ByteReader{Reader: c.InOrStdin()} input = &kio.ByteReader{Reader: c.InOrStdin()}
} }
@@ -156,10 +159,12 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
Inputs: []kio.Reader{input}, Inputs: []kio.Reader{input},
Filters: fltrs, Filters: fltrs,
Outputs: []kio.Writer{kio.TreeWriter{ Outputs: []kio.Writer{kio.TreeWriter{
Root: root, Root: root,
Writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
Fields: fields, Fields: fields,
Structure: kio.TreeStructure(r.structure)}}, Structure: kio.TreeStructure(r.structure),
OpenAPIFileName: openAPIFileName,
}},
}.Execute()) }.Execute())
} }

View File

@@ -90,6 +90,109 @@ spec:
} }
} }
func TestTreeCommand_subpkgs(t *testing.T) {
d, err := ioutil.TempDir("", "kustomize-tree-test")
defer os.RemoveAll(d)
if !assert.NoError(t, err) {
t.FailNow()
}
err = os.MkdirAll(filepath.Join(d, "subpkg"), 0700)
if !assert.NoError(t, err) {
t.FailNow()
}
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
apiVersion: v1
kind: Abstraction
metadata:
name: foo
configFn:
container:
image: gcr.io/example/reconciler:v1
annotations:
config.kubernetes.io/local-config: "true"
spec:
replicas: 1
---
kind: Deployment
metadata:
labels:
app: nginx2
name: foo
annotations:
app: nginx2
spec:
replicas: 1
---
kind: Service
metadata:
name: foo
annotations:
app: nginx
spec:
selector:
app: nginx
`), 0600)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(d, "subpkg", "f2.yaml"), []byte(`kind: Deployment
metadata:
labels:
app: nginx
name: bar
annotations:
app: nginx
spec:
replicas: 3
`), 0600)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(d, "Krmfile"), []byte(`apiVersion: kpt.dev/v1alpha1
kind: Krmfile
metadata:
name: mainpkg
openAPI:
definitions:
`), 0600)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(d, "subpkg", "Krmfile"), []byte(`apiVersion: kpt.dev/v1alpha1
kind: Krmfile
metadata:
name: subpkg
openAPI:
definitions:
`), 0600)
if !assert.NoError(t, err) {
return
}
// fmt the files
b := &bytes.Buffer{}
r := commands.GetTreeRunner("")
r.Command.SetArgs([]string{d})
r.Command.SetOut(b)
if !assert.NoError(t, r.Command.Execute()) {
return
}
if !assert.Equal(t, fmt.Sprintf(`%s
├── [Krmfile] Krmfile mainpkg
├── [f1.yaml] Deployment foo
├── [f1.yaml] Service foo
└── Pkg: subpkg
├── [Krmfile] Krmfile subpkg
└── [f2.yaml] Deployment bar
`, d), b.String()) {
return
}
}
func TestTreeCommand_stdin(t *testing.T) { func TestTreeCommand_stdin(t *testing.T) {
// fmt the files // fmt the files
b := &bytes.Buffer{} b := &bytes.Buffer{}

View File

@@ -5,13 +5,91 @@ package commands
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/pathutil"
) )
// cmdRunner interface holds executeCmd definition which executes respective command's
// implementation on single package
type cmdRunner interface {
executeCmd(w io.Writer, pkgPath string) error
}
// executeCmdOnPkgs struct holds the parameters necessary to
// execute the filter command on packages in rootPkgPath
type executeCmdOnPkgs struct {
rootPkgPath string
recurseSubPackages bool
needOpenAPI bool
cmdRunner cmdRunner
writer io.Writer
skipPkgPathPrint bool
}
// executeCmdOnPkgs takes the function definition for a command to be executed on single package, applies that definition
// recursively on all the subpackages present in rootPkgPath if recurseSubPackages is true, else applies the command on rootPkgPath only
func (e executeCmdOnPkgs) execute() error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
pkgsPaths, err := pathutil.DirsWithFile(e.rootPkgPath, openAPIFileName, e.recurseSubPackages)
if err != nil {
return err
}
if len(pkgsPaths) == 0 {
// at this point, there are no openAPI files in the rootPkgPath
if e.needOpenAPI {
// few executions need openAPI file to be present(ex: setters commands), if true throw an error
return errors.Errorf("unable to find %q in package %q", openAPIFileName, e.rootPkgPath)
}
// add root path for commands which doesn't need openAPI(ex: annotate, fmt)
pkgsPaths = []string{e.rootPkgPath}
}
for i := range pkgsPaths {
pkgPath := pkgsPaths[i]
// Add schema present in openAPI file for current package
if e.needOpenAPI {
if err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, openAPIFileName)); err != nil {
return err
}
}
if !e.skipPkgPathPrint {
fmt.Fprintf(e.writer, "%s/\n", pkgPath)
}
err := e.cmdRunner.executeCmd(e.writer, pkgPath)
if err != nil {
return err
}
if i != len(pkgsPaths)-1 {
fmt.Fprint(e.writer, "\n")
}
// Delete schema present in openAPI file for current package
if e.needOpenAPI {
if err := openapi.DeleteSchemaInFile(filepath.Join(pkgPath, openAPIFileName)); err != nil {
return err
}
}
}
return nil
}
// parseFieldPath parse a flag value into a field path // parseFieldPath parse a flag value into a field path
func parseFieldPath(path string) ([]string, error) { func parseFieldPath(path string) ([]string, error) {
// fixup '\.' so we don't split on it // fixup '\.' so we don't split on it

View File

@@ -0,0 +1,184 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package commands
import (
"bytes"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/errors"
)
func TestExecuteCmdOnPkgs(t *testing.T) {
var tests = []struct {
name string
recurse bool
pkgPath string
needOpenAPI bool
errMsg string
expectedOut string
}{
{
name: "need_Krmfile_error",
recurse: true,
needOpenAPI: true,
pkgPath: "subpkg1/subdir1",
errMsg: `unable to find "Krmfile" in package`,
},
{
name: "Krmfile_not_needed_no_err",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg1/subdir1",
expectedOut: `${baseDir}/subpkg1/subdir1/
`,
},
{
name: "executeCmd_returns_error",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg4",
expectedOut: `${baseDir}/subpkg4/
`,
errMsg: `this command returns an error if package has error.txt file`,
},
{
name: "executeCmd_prints_pkgpaths",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg2",
expectedOut: `${baseDir}/subpkg2/
${baseDir}/subpkg2/subpkg3/
`,
},
}
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
err = createTestDirStructure(dir)
if !assert.NoError(t, err) {
t.FailNow()
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
actual := &bytes.Buffer{}
r := &TestRunner{}
e := executeCmdOnPkgs{
needOpenAPI: test.needOpenAPI,
writer: actual,
rootPkgPath: filepath.Join(dir, test.pkgPath),
recurseSubPackages: test.recurse,
cmdRunner: r,
}
err := e.execute()
if test.errMsg == "" {
if !assert.NoError(t, err) {
t.FailNow()
}
} else {
if !assert.Error(t, err) {
t.FailNow()
}
if !assert.Contains(t, err.Error(), test.errMsg) {
t.FailNow()
}
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expectedOut, "${baseDir}", dir+"/", -1)
expectedNormalized := strings.Replace(
strings.Replace(expected, "\\", "/", -1),
"//", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}
func createTestDirStructure(dir string) error {
/*
Adds the folders to the input dir with following structure
dir
├── subpkg1
│   ├── Krmfile
│   └── subdir1
├── subpkg4
│   ├── Krmfile
│   └── error.txt
└── subpkg2
├── subpkg3
│ ├── Krmfile
│ └── subdir2
└── Krmfile
*/
err := os.MkdirAll(filepath.Join(dir, "subpkg1/subdir1"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg2/subpkg3/subdir2"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg4"), 0777|os.ModeDir)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg1", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2/subpkg3", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg4", "error.txt"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg4", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
return nil
}
type TestRunner struct{}
func (r *TestRunner) executeCmd(w io.Writer, pkgPath string) error {
children, err := ioutil.ReadDir(pkgPath)
if err != nil {
return err
}
for _, child := range children {
if child.Name() == "error.txt" {
return errors.Errorf("this command returns an error if package has error.txt file")
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
# 使用 kustomize 对 helm chart s进行修改 # 使用 kustomize 对 helm charts 进行修改
[last mile]: https://testingclouds.wordpress.com/2018/07/20/844/ [last mile]: https://testingclouds.wordpress.com/2018/07/20/844/
[stable chart]: https://github.com/helm/charts/tree/master/stable [stable chart]: https://github.com/helm/charts/tree/master/stable

View File

@@ -5,6 +5,6 @@ go 1.14
require ( require (
k8s.io/apimachinery v0.18.3 k8s.io/apimachinery v0.18.3
sigs.k8s.io/application v0.8.2 sigs.k8s.io/application v0.8.2
sigs.k8s.io/kustomize/kyaml v0.6.1 sigs.k8s.io/kustomize/kyaml v0.7.1
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )

View File

@@ -559,8 +559,8 @@ sigs.k8s.io/application v0.8.2 h1:XB7C33f7eW+1MbCJXoZa0+nP+R+S/VbAvYfCd3ufP1I=
sigs.k8s.io/application v0.8.2/go.mod h1:Mv+ht9RE/QNtITYCzRbt3XTIN6t6so6cInmiyg6wOIg= sigs.k8s.io/application v0.8.2/go.mod h1:Mv+ht9RE/QNtITYCzRbt3XTIN6t6so6cInmiyg6wOIg=
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/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak= sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI= 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=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=

View File

@@ -2,4 +2,4 @@ module sigs.k8s.io/kustomize/functions/examples/injection-tshirt-sizes
go 1.14 go 1.14
require sigs.k8s.io/kustomize/kyaml v0.6.1 require sigs.k8s.io/kustomize/kyaml v0.7.1

View File

@@ -217,6 +217,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -263,5 +265,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak= sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI= sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=

View File

@@ -2,4 +2,4 @@ module sigs.k8s.io/kustomize/functions/examples/template-go-nginx
go 1.14 go 1.14
require sigs.k8s.io/kustomize/kyaml v0.6.1 require sigs.k8s.io/kustomize/kyaml v0.7.1

View File

@@ -218,6 +218,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -264,5 +266,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak= sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI= sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=

View File

@@ -4,5 +4,5 @@ go 1.14
require ( require (
github.com/instrumenta/kubeval v0.0.0-20190918223246-8d013ec9fc56 github.com/instrumenta/kubeval v0.0.0-20190918223246-8d013ec9fc56
sigs.k8s.io/kustomize/kyaml v0.6.1 sigs.k8s.io/kustomize/kyaml v0.7.1
) )

View File

@@ -244,6 +244,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -294,7 +296,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak= sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI= sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -2,4 +2,4 @@ module sigs.k8s.io/kustomize/functions/examples/validator-resource-requests
go 1.14 go 1.14
require sigs.k8s.io/kustomize/kyaml v0.6.1 require sigs.k8s.io/kustomize/kyaml v0.7.1

View File

@@ -211,6 +211,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -257,5 +259,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak= sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI= sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=

View File

@@ -8,19 +8,19 @@ require (
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
k8s.io/client-go v0.17.3 k8s.io/client-go v0.17.3
sigs.k8s.io/kustomize/api v0.5.1 sigs.k8s.io/kustomize/api v0.6.1
sigs.k8s.io/kustomize/cmd/config v0.5.0 sigs.k8s.io/kustomize/cmd/config v0.6.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )
replace (
sigs.k8s.io/kustomize/api v0.5.1 => ../api
sigs.k8s.io/kustomize/cmd/config v0.5.0 => ../cmd/config
sigs.k8s.io/kustomize/kyaml => ../kyaml
)
exclude ( exclude (
github.com/russross/blackfriday v2.0.0+incompatible github.com/russross/blackfriday v2.0.0+incompatible
sigs.k8s.io/kustomize/api v0.2.0 sigs.k8s.io/kustomize/api v0.2.0
sigs.k8s.io/kustomize/cmd/config v0.2.0 sigs.k8s.io/kustomize/cmd/config v0.2.0
) )
replace sigs.k8s.io/kustomize/cmd/config v0.6.0 => ../cmd/config
replace sigs.k8s.io/kustomize/kyaml v0.7.1 => ../kyaml
replace sigs.k8s.io/kustomize/api v0.6.1 => ../api

View File

@@ -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=
@@ -627,6 +629,7 @@ golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -742,12 +745,16 @@ 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.19.0 h1:lAoR5okhSV/dIusodaQp5VbDpHMcKnvjqKYHU+AB3a4= sigs.k8s.io/cli-utils v0.20.1 h1:S3IM4Rmely9oWNAeytx46PhngTwdRxsJ4ixtoGWPc3o=
sigs.k8s.io/cli-utils v0.19.0/go.mod h1:B7KdqkSkHNIUn3cFbaR4aKUZMKtr+Benboi1w/HW/Fg= sigs.k8s.io/cli-utils v0.20.1/go.mod h1:fQkEMmLXduMNmUf1+dgQ5GRJa4OrrLMw3qzAN8YXAU8=
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/api v0.6.1 h1:O56V2VITIfJO4//MF5nvEdzqnzpPCyKdUFxyEU8EM2Y=
sigs.k8s.io/kustomize/api v0.6.1/go.mod h1:OdkkvVfqpfswawKJSPS4+3E0A91M44ugdmUp1UdZBEE=
sigs.k8s.io/kustomize/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=

View File

@@ -81,6 +81,11 @@ func newCmdAddConfigMap(
"from-env-file", "from-env-file",
"", "",
"Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).") "Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).")
cmd.Flags().BoolVar(
&flags.DisableNameSuffixHash,
"disableNameSuffixHash",
false,
"Disable the name suffix for the configmap")
return cmd return cmd
} }
@@ -126,4 +131,9 @@ func mergeFlagsIntoCmArgs(args *types.ConfigMapArgs, flags flagsAndArgs) {
args.EnvSources = append( args.EnvSources = append(
args.EnvSources, flags.EnvFileSource) args.EnvSources, flags.EnvFileSource)
} }
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
} }

View File

@@ -26,6 +26,8 @@ type flagsAndArgs struct {
Type string Type string
// Namespace of secret // Namespace of secret
Namespace string Namespace string
// Disable name suffix
DisableNameSuffixHash bool
} }
// Validate validates required fields are set to support structured generation. // Validate validates required fields are set to support structured generation.

View File

@@ -91,6 +91,11 @@ func newCmdAddSecret(
"namespace", "namespace",
"", "",
"Specify the namespace of the secret") "Specify the namespace of the secret")
cmd.Flags().BoolVar(
&flags.DisableNameSuffixHash,
"disableNameSuffixHash",
false,
"Disable the name suffix for the secret")
return cmd return cmd
} }
@@ -139,4 +144,9 @@ func mergeFlagsIntoGeneratorArgs(args *types.GeneratorArgs, flags flagsAndArgs)
args.EnvSources = append( args.EnvSources = append(
args.EnvSources, flags.EnvFileSource) args.EnvSources, flags.EnvFileSource)
} }
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
} }

View File

@@ -114,3 +114,14 @@ func TestMergeFlagsIntoSecretArgs_EnvSource(t *testing.T) {
t.Fatalf("expected env2") t.Fatalf("expected env2")
} }
} }
func TestMergeFlagsIntoSecretArgs_DisableNameSuffixHash(t *testing.T) {
k := &types.Kustomization{}
args := findOrMakeSecretArgs(k, "foo", "bar", "forbidden")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{DisableNameSuffixHash: true})
if k.SecretGenerator[0].Options.DisableNameSuffixHash != true {
t.Fatalf("expected true")
}
}

View File

@@ -39,5 +39,6 @@ func RunFix(fSys filesys.FileSystem) error {
return err return err
} }
m.FixKustomizationPreMarshalling()
return mf.Write(m) return mf.Write(m)
} }

View File

@@ -7,6 +7,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/google/go-cmp/cmp"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils" testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils"
) )
@@ -31,3 +32,104 @@ func TestFix(t *testing.T) {
t.Errorf("expected kind in kustomization") t.Errorf("expected kind in kustomization")
} }
} }
func TestFixOutdatedPatchesFieldTitle(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
cmd := NewCmdFix(fSys)
err := cmd.RunE(cmd, nil)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
if !strings.Contains(string(content), "apiVersion: ") {
t.Errorf("expected apiVersion in kustomization")
}
if !strings.Contains(string(content), "kind: Kustomization") {
t.Errorf("expected kind in kustomization")
}
if diff := cmp.Diff(expected, content); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestRenameAndKeepOutdatedPatchesField(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Deployment
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
`)
expected := []byte(`
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
- path: patch1.yaml
target:
kind: Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
cmd := NewCmdFix(fSys)
err := cmd.RunE(cmd, nil)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
if !strings.Contains(string(content), "apiVersion: ") {
t.Errorf("expected apiVersion in kustomization")
}
if !strings.Contains(string(content), "kind: Kustomization") {
t.Errorf("expected kind in kustomization")
}
if diff := cmp.Diff(expected, content); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}

View File

@@ -145,6 +145,47 @@ func TestSetImage(t *testing.T) {
" newTag: my-tag2", " newTag: my-tag2",
}}, }},
}, },
{
description: "override file with patch",
given: given{
args: []string{"image1=foo.bar.foo:8800/foo/image1:foo-bar"},
infileImages: []string{
"images:",
"- name: image1",
" newName: my-image1",
" newTag: my-tag",
"- name: image2",
" newName: my-image2",
" newTag: my-tag2",
"patchesJson6902:",
"- patch: |-",
" - op: remove",
" path: /spec/selector",
" target:",
" kind: Service",
" name: foo",
" version: v1",
},
},
expected: expected{
fileOutput: []string{
"images:",
"- name: image1",
" newName: foo.bar.foo:8800/foo/image1",
" newTag: foo-bar",
"- name: image2",
" newName: my-image2",
" newTag: my-tag2",
"patchesJson6902:",
"- patch: |-",
" - op: remove",
" path: /spec/selector",
" target:",
" kind: Service",
" name: foo",
" version: v1",
}},
},
{ {
description: "override new tag and new name with just a new tag", description: "override new tag and new name with just a new tag",
given: given{ given: given{

View File

@@ -170,7 +170,6 @@ func (mf *kustomizationFile) Write(kustomization *types.Kustomization) error {
if kustomization == nil { if kustomization == nil {
return errors.New("util: kustomization file arg is nil") return errors.New("util: kustomization file arg is nil")
} }
kustomization.FixKustomizationPreMarshalling()
data, err := mf.marshal(kustomization) data, err := mf.marshal(kustomization)
if err != nil { if err != nil {
return err return err

View File

@@ -338,103 +338,6 @@ kind: Kustomization
} }
} }
func TestRenameAndKeepOutdatedPatchesField(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Deployment
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
`)
expected := []byte(`
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
- path: patch1.yaml
target:
kind: Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
mf, err := NewKustomizationFile(fSys)
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
kustomization, err := mf.Read()
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
if err = mf.Write(kustomization); err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
bytes, _ := fSys.ReadFile(mf.path)
if diff := cmp.Diff(expected, bytes); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestFixOutdatedPatchesFieldTitle(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
mf, err := NewKustomizationFile(fSys)
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
kustomization, err := mf.Read()
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
if err = mf.Write(kustomization); err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
bytes, _ := fSys.ReadFile(mf.path)
if diff := cmp.Diff(expected, bytes); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestUnknownFieldInKustomization(t *testing.T) { func TestUnknownFieldInKustomization(t *testing.T) {
kContent := []byte(` kContent := []byte(`
foo: foo:

10
kyaml/ext/ext.go Normal file
View File

@@ -0,0 +1,10 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package ext
// GetIgnoreFileName returns the name for ignore files in
// packages. It can be overridden by tools using this library.
var GetIgnoreFileName = func() string {
return ".krmignore"
}

View File

@@ -154,13 +154,17 @@ func (c *Filter) setupExec() {
// getArgs returns the command + args to run to spawn the container // getArgs returns the command + args to run to spawn the container
func (c *Filter) getCommand() (string, []string) { func (c *Filter) getCommand() (string, []string) {
network := runtimeutil.NetworkNameNone
if c.ContainerSpec.Network {
network = runtimeutil.NetworkNameHost
}
// run the container using docker. this is simpler than using the docker // run the container using docker. this is simpler than using the docker
// libraries, and ensures things like auth work the same as if the container // libraries, and ensures things like auth work the same as if the container
// was run from the cli. // was run from the cli.
args := []string{"run", args := []string{"run",
"--rm", // delete the container afterward "--rm", // delete the container afterward
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR", // attach stdin, stdout, stderr "-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR", // attach stdin, stdout, stderr
"--network", string(c.ContainerSpec.Network.Name), "--network", string(network),
// added security options // added security options
"--user", c.User.String(), "--user", c.User.String(),
@@ -186,10 +190,5 @@ func NewContainer(spec runtimeutil.ContainerSpec) Filter {
f.ContainerSpec.User = runtimeutil.UserNobody f.ContainerSpec.User = runtimeutil.UserNobody
} }
// default network name is none
if f.ContainerSpec.Network.Name == "" {
f.ContainerSpec.Network.Name = runtimeutil.NetworkNameNone
}
return f return f
} }

View File

@@ -55,17 +55,15 @@ metadata:
"run", "run",
"--rm", "--rm",
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR", "-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR",
"--network", "test-1", "--network", "host",
"--user", "nobody", "--user", "nobody",
"--security-opt=no-new-privileges", "--security-opt=no-new-privileges",
}, },
instance: NewContainer( instance: NewContainer(
runtimeutil.ContainerSpec{ runtimeutil.ContainerSpec{
Image: "example.com:version", Image: "example.com:version",
Network: runtimeutil.ContainerNetwork{ Network: true,
Name: "test-1", User: "nobody",
},
User: "nobody",
}, },
), ),
}, },

View File

@@ -38,8 +38,8 @@ const (
type ContainerNetworkName string type ContainerNetworkName string
const ( const (
NetworkNameNone ContainerNetworkName = "none" NetworkNameNone ContainerNetworkName = "none"
NetworkNameEmpty ContainerNetworkName = "" NetworkNameHost ContainerNetworkName = "host"
) )
const defaultEnvValue string = "true" const defaultEnvValue string = "true"
@@ -166,7 +166,7 @@ type ContainerSpec struct {
Image string `json:"image,omitempty" yaml:"image,omitempty"` Image string `json:"image,omitempty" yaml:"image,omitempty"`
// Network defines network specific configuration // Network defines network specific configuration
Network ContainerNetwork `json:"network,omitempty" yaml:"network,omitempty"` Network bool `json:"network,omitempty" yaml:"network,omitempty"`
// Mounts are the storage or directories to mount into the container // Mounts are the storage or directories to mount into the container
StorageMounts []StorageMount `json:"mounts,omitempty" yaml:"mounts,omitempty"` StorageMounts []StorageMount `json:"mounts,omitempty" yaml:"mounts,omitempty"`
@@ -178,15 +178,6 @@ type ContainerSpec struct {
Env []string `json:"envs,omitempty" yaml:"envs,omitempty"` Env []string `json:"envs,omitempty" yaml:"envs,omitempty"`
} }
// ContainerNetwork
type ContainerNetwork struct {
// Required specifies that function requires a network
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
// Name is the name of the network to use from a container
Name ContainerNetworkName `json:"name,omitempty" yaml:"name,omitempty"`
}
// StarlarkSpec defines how to run a function as a starlark program // StarlarkSpec defines how to run a function as a starlark program
type StarlarkSpec struct { type StarlarkSpec struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"` Name string `json:"name,omitempty" yaml:"name,omitempty"`
@@ -237,7 +228,6 @@ func GetFunctionSpec(n *yaml.RNode) *FunctionSpec {
} }
if fn := getFunctionSpecFromAnnotation(n, meta); fn != nil { if fn := getFunctionSpecFromAnnotation(n, meta); fn != nil {
fn.Container.Network.Name = NetworkNameEmpty
fn.StorageMounts = []StorageMount{} fn.StorageMounts = []StorageMount{}
return fn return fn
} }

View File

@@ -1208,14 +1208,12 @@ metadata:
config.kubernetes.io/function: |- config.kubernetes.io/function: |-
container: container:
image: foo:v1.0.0 image: foo:v1.0.0
network: network: true
required: true
`, `,
expectedFn: ` expectedFn: `
container: container:
image: foo:v1.0.0 image: foo:v1.0.0
network: network: true
required: true
`, `,
}, },
@@ -1324,8 +1322,7 @@ metadata:
configFn: configFn:
container: container:
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
network: network: true
required: true
`, `,
required: true, required: true,
}, },
@@ -1337,8 +1334,7 @@ metadata:
configFn: configFn:
container: container:
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
network: network: false
required: false
`, `,
required: false, required: false,
}, },
@@ -1363,8 +1359,7 @@ metadata:
config.kubernetes.io/function: | config.kubernetes.io/function: |
container: container:
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
network: network: true
required: true
`, `,
required: true, required: true,
}, },
@@ -1376,7 +1371,7 @@ metadata:
return return
} }
fn := GetFunctionSpec(cfg) fn := GetFunctionSpec(cfg)
assert.Equal(t, tc.required, fn.Container.Network.Required) assert.Equal(t, tc.required, fn.Container.Network)
} }
} }

View File

@@ -8,6 +8,7 @@ require (
github.com/go-openapi/spec v0.19.5 github.com/go-openapi/spec v0.19.5
github.com/go-openapi/strfmt v0.19.5 github.com/go-openapi/strfmt v0.19.5
github.com/go-openapi/validate v0.19.8 github.com/go-openapi/validate v0.19.8
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d
github.com/sergi/go-diff v1.1.0 github.com/sergi/go-diff v1.1.0
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0

View File

@@ -145,6 +145,8 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk= github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=

View File

@@ -0,0 +1,100 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kio
import (
"os"
"path/filepath"
"strings"
"github.com/monochromegane/go-gitignore"
"sigs.k8s.io/kustomize/kyaml/ext"
)
// ignoreFilesMatcher handles `.krmignore` files, which allows for ignoring
// 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
// file or folder matches any of the patterns in the .krmignore file for the
// package, it will be excluded.
//
// It works as follows:
//
// * It will look for .krmignore file in the top folder and on the top level
// of any subpackages. Subpackages are defined by the presence of a Krmfile
// in the folder.
// * `.krmignore` files only cover files and folders for the package in which
// it is defined. So ignore patterns defined in a parent package does not
// affect which files are ignored from a subpackage.
// * An ignore pattern can not ignore a subpackage. So even if the parent
// package contains a pattern that ignores the directory foo, if foo is a
// subpackage, it will still be included if the IncludeSubpackages property
// is set to true
type ignoreFilesMatcher struct {
matchers []matcher
}
// 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,
// we just add a matcher that match nothing.
func (i *ignoreFilesMatcher) readIgnoreFile(path string) error {
i.verifyPath(path)
m, err := gitignore.NewGitIgnore(filepath.Join(path, ext.GetIgnoreFileName()))
if err != nil {
if os.IsNotExist(err) {
i.matchers = append(i.matchers, matcher{
matcher: gitignore.DummyIgnoreMatcher(false),
basePath: path,
})
return nil
}
return err
}
i.matchers = append(i.matchers, matcher{
matcher: m,
basePath: path,
})
return nil
}
// verifyPath checks whether the top matcher on the stack
// is correct for the provided filepath. Matchers are removed once
// we encounter a filepath that is not a subpath of the basepath for
// the matcher.
func (i *ignoreFilesMatcher) verifyPath(path string) {
for j := len(i.matchers) - 1; j >= 0; j-- {
matcher := i.matchers[j]
if strings.HasPrefix(path, matcher.basePath) || path == matcher.basePath {
i.matchers = i.matchers[:j+1]
return
}
}
}
// matchFile checks whether the file given by the provided path matches
// any of the patterns in the .krmignore file for the package.
func (i *ignoreFilesMatcher) matchFile(path string) bool {
if len(i.matchers) == 0 {
return false
}
i.verifyPath(filepath.Dir(path))
return i.matchers[len(i.matchers)-1].matcher.Match(path, false)
}
// matchFile checks whether the directory given by the provided path matches
// any of the patterns in the .krmignore file for the package.
func (i *ignoreFilesMatcher) matchDir(path string) bool {
if len(i.matchers) == 0 {
return false
}
i.verifyPath(path)
return i.matchers[len(i.matchers)-1].matcher.Match(path, true)
}
// matcher wraps the gitignore matcher and the path to the folder
// where the file was found.
type matcher struct {
matcher gitignore.IgnoreMatcher
basePath string
}

View File

@@ -0,0 +1,249 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kio
import (
"io/ioutil"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIgnoreFilesMatcher_readIgnoreFile(t *testing.T) {
testCases := []struct {
name string
writeIgnoreFile bool
isMatch bool
}{
{
name: "has .krmignore file",
writeIgnoreFile: true,
isMatch: true,
},
{
name: "no .krmignore file",
writeIgnoreFile: false,
isMatch: false,
},
}
for i := range testCases {
test := testCases[i]
t.Run(test.name, func(t *testing.T) {
dir, err := ioutil.TempDir("", "kyaml-test")
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
if test.writeIgnoreFile {
ignoreFilePath := filepath.Join(dir, ".krmignore")
err = ioutil.WriteFile(ignoreFilePath, []byte(`
testfile.yaml
`), 0600)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
}
testFilePath := filepath.Join(dir, "testfile.yaml")
err = ioutil.WriteFile(testFilePath, []byte{}, 0600)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
ignoreFilesMatcher := ignoreFilesMatcher{}
err = ignoreFilesMatcher.readIgnoreFile(dir)
if !assert.NoError(t, err) {
t.FailNow()
}
assert.Equal(t, test.isMatch, ignoreFilesMatcher.matchFile(testFilePath))
})
}
}
var (
readFileA = []byte(`
a: a
---
c: c
`)
readFileB = []byte(`
b: b
`)
)
func TestLocalPackageReader_Read_ignoreFile(t *testing.T) {
testCases := []struct {
name string
directories []string
files map[string][]byte
expected []string
}{
{
name: "ignore file",
directories: []string{
filepath.Join("a", "b"),
filepath.Join("a", "c"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("a", "b", "a_test.yaml"): readFileA,
filepath.Join("a", "c", "c_test.yaml"): readFileB,
filepath.Join(".krmignore"): []byte(`
a/c/c_test.yaml
`,
),
},
expected: []string{
`a: a`,
`c: c`,
},
},
{
name: "ignore folder",
directories: []string{
filepath.Join("a", "b"),
filepath.Join("a", "c"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("a", "b", "a_test.yaml"): readFileA,
filepath.Join("a", "c", "c_test.yaml"): readFileB,
filepath.Join(".krmignore"): []byte(`
a/c
`,
),
},
expected: []string{
`a: a`,
`c: c`,
},
},
{
name: "krmignore file in subpackage",
directories: []string{
filepath.Join("a", "c"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("a", "c", "a_test.yaml"): readFileA,
filepath.Join("a", "c", "c_test.yaml"): readFileB,
filepath.Join(".krmignore"): []byte(`
d/e/f.yaml
`,
),
filepath.Join("a", "c", "pkgFile"): {},
filepath.Join("a", "c", ".krmignore"): []byte(`
a_test.yaml
`),
},
expected: []string{
`b: b`,
},
},
{
name: "krmignore files does not affect subpackages",
directories: []string{
filepath.Join("a", "c"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("a", "c", "a_test.yaml"): readFileA,
filepath.Join("a", "c", "c_test.yaml"): readFileB,
filepath.Join(".krmignore"): []byte(`
a/c/c_test.yaml
`,
),
filepath.Join("a", "c", "pkgFile"): {},
filepath.Join("a", "c", ".krmignore"): []byte(`
a_test.yaml
`),
},
expected: []string{
`b: b`,
},
},
{
name: "handles a combination of packages and directories",
directories: []string{
filepath.Join("a"),
filepath.Join("d", "e"),
filepath.Join("f"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("d", "pkgFile"): {},
filepath.Join("d", "e", "pkgFile"): {},
filepath.Join("f", "pkgFile"): {},
filepath.Join("manifest.yaml"): []byte(`root: root`),
filepath.Join("a", "manifest.yaml"): []byte(`a: a`),
filepath.Join("d", "manifest.yaml"): []byte(`d: d`),
filepath.Join("d", "e", "manifest.yaml"): []byte(`e: e`),
filepath.Join("f", "manifest.yaml"): []byte(`f: f`),
filepath.Join("d", ".krmignore"): []byte(`
manifest.yaml
`),
},
expected: []string{
`a: a`,
`e: e`,
`f: f`,
`root: root`,
},
},
{
name: "ignore file can exclude subpackages",
directories: []string{
filepath.Join("a"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("a", "pkgFile"): {},
filepath.Join("manifest.yaml"): []byte(`root: root`),
filepath.Join("a", "manifest.yaml"): []byte(`a: a`),
filepath.Join(".krmignore"): []byte(`
a
`),
},
expected: []string{
`root: root`,
},
},
}
for i := range testCases {
test := testCases[i]
t.Run(test.name, func(t *testing.T) {
s := SetupDirectories(t, test.directories...)
defer s.Clean()
for path, content := range test.files {
s.WriteFile(t, path, content)
}
// empty path
rfr := LocalPackageReader{
PackagePath: s.Root,
IncludeSubpackages: true,
PackageFileName: "pkgFile",
OmitReaderAnnotations: true,
}
nodes, err := rfr.Read()
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
if !assert.Len(t, nodes, len(test.expected)) {
assert.FailNow(t, "wrong number items")
}
for i, node := range nodes {
val, err := node.String()
assert.NoError(t, err)
want := strings.ReplaceAll(test.expected[i], "${SEP}", string(filepath.Separator))
assert.Equal(t, strings.TrimSpace(want), strings.TrimSpace(val))
}
})
}
}

View File

@@ -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)
@@ -184,8 +185,13 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) {
var operand ResourceNodeSlice var operand ResourceNodeSlice
var pathRelativeTo string var pathRelativeTo string
r.PackagePath = filepath.Clean(r.PackagePath) var err error
err := filepath.Walk(r.PackagePath, func( ignoreFilesMatcher := &ignoreFilesMatcher{}
r.PackagePath, err = filepath.Abs(r.PackagePath)
if err != nil {
return nil, errors.Wrap(err)
}
err = filepath.Walk(r.PackagePath, func(
path string, info os.FileInfo, err error) error { path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return errors.Wrap(err) return errors.Wrap(err)
@@ -194,9 +200,10 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) {
// is this the user specified path? // is this the user specified path?
if path == r.PackagePath { if path == r.PackagePath {
if info.IsDir() { if info.IsDir() {
// skip the root package directory // skip the root package directory, but check for a
// .krmignore file first.
pathRelativeTo = r.PackagePath pathRelativeTo = r.PackagePath
return nil return ignoreFilesMatcher.readIgnoreFile(path)
} }
// user specified path is a file rather than a directory. // user specified path is a file rather than a directory.
@@ -206,9 +213,9 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) {
// check if we should skip the directory or file // check if we should skip the directory or file
if info.IsDir() { if info.IsDir() {
return r.ShouldSkipDir(path) return r.shouldSkipDir(path, ignoreFilesMatcher)
} }
if match, err := r.ShouldSkipFile(info); err != nil { if match, err := r.shouldSkipFile(path, ignoreFilesMatcher); err != nil {
return err return err
} else if !match { } else if !match {
// skip this file // skip this file
@@ -250,11 +257,16 @@ func (r *LocalPackageReader) readFile(path string, _ os.FileInfo) ([]*yaml.RNode
return rr.Read() return rr.Read()
} }
// ShouldSkipFile returns true if the file should be skipped // shouldSkipFile returns true if the file should be skipped
func (r *LocalPackageReader) ShouldSkipFile(info os.FileInfo) (bool, error) { func (r *LocalPackageReader) shouldSkipFile(path string, matcher *ignoreFilesMatcher) (bool, error) {
// check if the file is covered by a .krmignore file.
if matcher.matchFile(path) {
return false, nil
}
// check if the files are in scope // check if the files are in scope
for _, g := range r.MatchFilesGlob { for _, g := range r.MatchFilesGlob {
if match, err := filepath.Match(g, info.Name()); err != nil { if match, err := filepath.Match(g, filepath.Base(path)); err != nil {
return false, errors.Wrap(err) return false, errors.Wrap(err)
} else if match { } else if match {
return true, nil return true, nil
@@ -273,8 +285,12 @@ 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) error { func (r *LocalPackageReader) shouldSkipDir(path string, matcher *ignoreFilesMatcher) error {
if matcher.matchDir(path) {
return filepath.SkipDir
}
if r.PackageFileName == "" { if r.PackageFileName == "" {
return nil return nil
} }
@@ -288,5 +304,5 @@ func (r *LocalPackageReader) ShouldSkipDir(path string) error {
if !r.IncludeSubpackages { if !r.IncludeSubpackages {
return filepath.SkipDir return filepath.SkipDir
} }
return nil return matcher.readIgnoreFile(path)
} }

View File

@@ -4,59 +4,14 @@
package kio_test package kio_test
import ( import (
"io/ioutil"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
. "sigs.k8s.io/kustomize/kyaml/kio" . "sigs.k8s.io/kustomize/kyaml/kio"
// "sigs.k8s.io/kustomize/kyaml/testutil"
) )
// setup creates directories and files for testing
type setup struct {
// root is the tmp directory
root string
}
// setupDirectories creates directories for reading test configuration from
func setupDirectories(t *testing.T, dirs ...string) setup {
d, err := ioutil.TempDir("", "kyaml-test")
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
err = os.Chdir(d)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
for _, s := range dirs {
err = os.MkdirAll(s, 0700)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
}
return setup{root: d}
}
// writeFile writes a file under the test directory
func (s setup) writeFile(t *testing.T, path string, value []byte) {
err := os.MkdirAll(filepath.Dir(filepath.Join(s.root, path)), 0700)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
err = ioutil.WriteFile(filepath.Join(s.root, path), value, 0600)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
}
// clean deletes the test config
func (s setup) clean() {
os.RemoveAll(s.root)
}
var readFileA = []byte(`--- var readFileA = []byte(`---
a: b #first a: b #first
--- ---
@@ -94,18 +49,18 @@ func TestLocalPackageReader_Read_empty(t *testing.T) {
} }
func TestLocalPackageReader_Read_pkg(t *testing.T) { func TestLocalPackageReader_Read_pkg(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("b_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("b_test.yaml"), readFileB)
s.writeFile(t, filepath.Join("c_test.yaml"), readFileC) s.WriteFile(t, filepath.Join("c_test.yaml"), readFileC)
s.writeFile(t, filepath.Join("d_test.yaml"), readFileD) s.WriteFile(t, filepath.Join("d_test.yaml"), readFileD)
paths := []struct { paths := []struct {
path string path string
}{ }{
{path: "./"}, {path: "./"},
{path: s.root}, {path: s.Root},
} }
for _, p := range paths { for _, p := range paths {
rfr := LocalPackageReader{PackagePath: p.path} rfr := LocalPackageReader{PackagePath: p.path}
@@ -167,13 +122,13 @@ metadata:
} }
func TestLocalPackageReader_Read_JSON(t *testing.T) { func TestLocalPackageReader_Read_JSON(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a_test.json"), []byte(`{ s.WriteFile(t, filepath.Join("a_test.json"), []byte(`{
"a": "b" "a": "b"
}`)) }`))
s.writeFile(t, filepath.Join("b_test.json"), []byte(`{ s.WriteFile(t, filepath.Join("b_test.json"), []byte(`{
"e": "f", "e": "f",
"g": { "g": {
"h": ["i", "j"] "h": ["i", "j"]
@@ -184,7 +139,7 @@ func TestLocalPackageReader_Read_JSON(t *testing.T) {
path string path string
}{ }{
{path: "./"}, {path: "./"},
{path: s.root}, {path: s.Root},
} }
for _, p := range paths { for _, p := range paths {
rfr := LocalPackageReader{PackagePath: p.path, MatchFilesGlob: []string{"*.json"}} rfr := LocalPackageReader{PackagePath: p.path, MatchFilesGlob: []string{"*.json"}}
@@ -217,16 +172,16 @@ func TestLocalPackageReader_Read_JSON(t *testing.T) {
} }
func TestLocalPackageReader_Read_file(t *testing.T) { func TestLocalPackageReader_Read_file(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("b_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("b_test.yaml"), readFileB)
paths := []struct { paths := []struct {
path string path string
}{ }{
{path: "./"}, {path: "./"},
{path: s.root}, {path: s.Root},
} }
for _, p := range paths { for _, p := range paths {
rfr := LocalPackageReader{PackagePath: filepath.Join(p.path, "a_test.yaml")} rfr := LocalPackageReader{PackagePath: filepath.Join(p.path, "a_test.yaml")}
@@ -265,16 +220,16 @@ metadata:
} }
func TestLocalPackageReader_Read_pkgOmitAnnotations(t *testing.T) { func TestLocalPackageReader_Read_pkgOmitAnnotations(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("b_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("b_test.yaml"), readFileB)
paths := []struct { paths := []struct {
path string path string
}{ }{
{path: "./"}, {path: "./"},
{path: s.root}, {path: s.Root},
} }
for _, p := range paths { for _, p := range paths {
// empty path // empty path
@@ -313,16 +268,16 @@ g:
} }
func TestLocalPackageReader_Read_nestedDirs(t *testing.T) { func TestLocalPackageReader_Read_nestedDirs(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("a", "b", "b_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("a", "b", "b_test.yaml"), readFileB)
paths := []struct { paths := []struct {
path string path string
}{ }{
{path: "./"}, {path: "./"},
{path: s.root}, {path: s.Root},
} }
for _, p := range paths { for _, p := range paths {
// empty path // empty path
@@ -374,13 +329,13 @@ metadata:
} }
func TestLocalPackageReader_Read_matchRegex(t *testing.T) { func TestLocalPackageReader_Read_matchRegex(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("a", "b", "b_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("a", "b", "b_test.yaml"), readFileB)
// empty path // empty path
rfr := LocalPackageReader{PackagePath: s.root, MatchFilesGlob: []string{`a*.yaml`}} rfr := LocalPackageReader{PackagePath: s.Root, MatchFilesGlob: []string{`a*.yaml`}}
nodes, err := rfr.Read() nodes, err := rfr.Read()
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
assert.FailNow(t, err.Error()) assert.FailNow(t, err.Error())
@@ -414,14 +369,14 @@ metadata:
} }
func TestLocalPackageReader_Read_skipSubpackage(t *testing.T) { func TestLocalPackageReader_Read_skipSubpackage(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("a", "c", "c_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("a", "c", "c_test.yaml"), readFileB)
s.writeFile(t, filepath.Join("a", "c", "pkgFile"), pkgFile) s.WriteFile(t, filepath.Join("a", "c", "pkgFile"), pkgFile)
// empty path // empty path
rfr := LocalPackageReader{PackagePath: s.root, PackageFileName: "pkgFile"} rfr := LocalPackageReader{PackagePath: s.Root, PackageFileName: "pkgFile"}
nodes, err := rfr.Read() nodes, err := rfr.Read()
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
assert.FailNow(t, err.Error()) assert.FailNow(t, err.Error())
@@ -455,14 +410,14 @@ metadata:
} }
func TestLocalPackageReader_Read_includeSubpackage(t *testing.T) { func TestLocalPackageReader_Read_includeSubpackage(t *testing.T) {
s := setupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c")) s := SetupDirectories(t, filepath.Join("a", "b"), filepath.Join("a", "c"))
defer s.clean() defer s.Clean()
s.writeFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA) s.WriteFile(t, filepath.Join("a", "b", "a_test.yaml"), readFileA)
s.writeFile(t, filepath.Join("a", "c", "c_test.yaml"), readFileB) s.WriteFile(t, filepath.Join("a", "c", "c_test.yaml"), readFileB)
s.writeFile(t, filepath.Join("a", "c", "pkgFile"), pkgFile) s.WriteFile(t, filepath.Join("a", "c", "pkgFile"), pkgFile)
// empty path // empty path
rfr := LocalPackageReader{PackagePath: s.root, IncludeSubpackages: true, PackageFileName: "pkgFile"} rfr := LocalPackageReader{PackagePath: s.Root, IncludeSubpackages: true, PackageFileName: "pkgFile"}
nodes, err := rfr.Read() nodes, err := rfr.Read()
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
assert.FailNow(t, err.Error()) assert.FailNow(t, err.Error())

55
kyaml/kio/testing.go Normal file
View File

@@ -0,0 +1,55 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kio
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
// Setup creates directories and files for testing
type Setup struct {
// root is the tmp directory
Root string
}
// setupDirectories creates directories for reading test configuration from
func SetupDirectories(t *testing.T, dirs ...string) Setup {
d, err := ioutil.TempDir("", "kyaml-test")
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
err = os.Chdir(d)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
for _, s := range dirs {
err = os.MkdirAll(s, 0700)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
}
return Setup{Root: d}
}
// writeFile writes a file under the test directory
func (s Setup) WriteFile(t *testing.T, path string, value []byte) {
err := os.MkdirAll(filepath.Dir(filepath.Join(s.Root, path)), 0700)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
err = ioutil.WriteFile(filepath.Join(s.Root, path), value, 0600)
if !assert.NoError(t, err) {
assert.FailNow(t, err.Error())
}
}
// clean deletes the test config
func (s Setup) Clean() {
os.RemoveAll(s.Root)
}

View File

@@ -6,6 +6,7 @@ package kio
import ( import (
"fmt" "fmt"
"io" "io"
"os"
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
@@ -33,10 +34,11 @@ var GraphStructures = []string{string(TreeStructureGraph), string(TreeStructureP
// TODO(pwittrock): test this package better. it is lower-risk since it is only // TODO(pwittrock): test this package better. it is lower-risk since it is only
// used for printing rather than updating or editing. // used for printing rather than updating or editing.
type TreeWriter struct { type TreeWriter struct {
Writer io.Writer Writer io.Writer
Root string Root string
Fields []TreeWriterField Fields []TreeWriterField
Structure TreeStructure Structure TreeStructure
OpenAPIFileName string
} }
// TreeWriterField configures a Resource field to be included in the tree // TreeWriterField configures a Resource field to be included in the tree
@@ -72,7 +74,7 @@ func (p TreeWriter) packageStructure(nodes []*yaml.RNode) error {
// create a new branch for the package // create a new branch for the package
createOk := pkg != "." // special edge case logic for tree on current working dir createOk := pkg != "." // special edge case logic for tree on current working dir
if createOk { if createOk {
branch = branch.AddBranch(pkg) branch = branch.AddBranch(branchName(p.Root, pkg, p.OpenAPIFileName))
} }
// cache the branch for this package // cache the branch for this package
@@ -91,6 +93,19 @@ func (p TreeWriter) packageStructure(nodes []*yaml.RNode) error {
return err return err
} }
// branchName takes the root directory and relative path to the directory
// and returns the branch name
func branchName(root, dirRelPath, openAPIFileName string) string {
name := filepath.Base(dirRelPath)
_, err := os.Stat(filepath.Join(root, dirRelPath, openAPIFileName))
if !os.IsNotExist(err) {
// add Pkg: prefix indicating that it is a separate package as it has
// openAPIFile
return fmt.Sprintf("Pkg: %s", name)
}
return name
}
// Write writes the ascii tree to p.Writer // Write writes the ascii tree to p.Writer
func (p TreeWriter) Write(nodes []*yaml.RNode) error { func (p TreeWriter) Write(nodes []*yaml.RNode) error {
switch p.Structure { switch p.Structure {

View File

@@ -6,7 +6,6 @@ package kio_test
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -76,9 +75,9 @@ spec:
└── foo-package └── foo-package
├── [f1.yaml] Deployment default/foo ├── [f1.yaml] Deployment default/foo
├── [f1.yaml] Service default/foo ├── [f1.yaml] Service default/foo
└── foo-package%s3 └── 3
└── [f3.yaml] Deployment default/foo └── [f3.yaml] Deployment default/foo
`, string(filepath.Separator)), out.String()) { `), out.String()) {
t.FailNow() t.FailNow()
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -95,7 +95,7 @@ func openapiKustomizationapiSwaggerJson() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "openapi/kustomizationapi/swagger.json", size: 3127, mode: os.FileMode(420), modTime: time.Unix(1586844916, 0)} info := bindataFileInfo{name: "openapi/kustomizationapi/swagger.json", size: 3127, mode: os.FileMode(420), modTime: time.Unix(1586909905, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }

Some files were not shown because too many files have changed in this diff Show More