mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-15 10:58:18 +00:00
Compare commits
202 Commits
api/v0.6.3
...
api/v0.6.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
881d33ac5c | ||
|
|
842e4f5dc5 | ||
|
|
ef612286e4 | ||
|
|
636c9fcddf | ||
|
|
333945d361 | ||
|
|
c5cd539b01 | ||
|
|
4b89c2afa2 | ||
|
|
630fc9b973 | ||
|
|
a468743b81 | ||
|
|
e9a74b87e3 | ||
|
|
64f8d2ae38 | ||
|
|
5ab320c216 | ||
|
|
6131f86d23 | ||
|
|
e7609559ce | ||
|
|
c2bdac7a6b | ||
|
|
4cc2c4f623 | ||
|
|
155c42679c | ||
|
|
88239445ce | ||
|
|
d66fc462ec | ||
|
|
6788af083b | ||
|
|
df0576a270 | ||
|
|
f4d8ebb1da | ||
|
|
0acac39640 | ||
|
|
65db82df0c | ||
|
|
68951bb37e | ||
|
|
b18910aa6d | ||
|
|
f780f7a3c2 | ||
|
|
7966386615 | ||
|
|
2130ba72cc | ||
|
|
94d26ba53a | ||
|
|
c53f31ca4f | ||
|
|
b58075cbc3 | ||
|
|
b3e82a2fe7 | ||
|
|
78c26f55b5 | ||
|
|
ec2a6e4e4b | ||
|
|
886f73aa0f | ||
|
|
73d91dda6e | ||
|
|
9f06376ab2 | ||
|
|
e785bab474 | ||
|
|
8f80a898b6 | ||
|
|
fe84d119d6 | ||
|
|
03b847a749 | ||
|
|
9d2f257acf | ||
|
|
129b25ceff | ||
|
|
57f4ea5354 | ||
|
|
ec2cc2d421 | ||
|
|
712eb6d276 | ||
|
|
a04e3a575c | ||
|
|
03e2fed925 | ||
|
|
c37b3b2525 | ||
|
|
ceeba8764f | ||
|
|
04d133a66f | ||
|
|
99aaa80e1d | ||
|
|
1f806b0aa2 | ||
|
|
1f697e3792 | ||
|
|
c0ecd1d1ad | ||
|
|
3923c63182 | ||
|
|
9943e74187 | ||
|
|
3b504fa3e5 | ||
|
|
9fb25fc5a7 | ||
|
|
4d99217a7c | ||
|
|
0834e152b2 | ||
|
|
ff276af317 | ||
|
|
3b79944190 | ||
|
|
d8d57eae29 | ||
|
|
c803ca83a4 | ||
|
|
6bed275234 | ||
|
|
8e5df26e4c | ||
|
|
3fed68b694 | ||
|
|
0e59c36d03 | ||
|
|
00fdf71dc3 | ||
|
|
be327e7443 | ||
|
|
be8d2fe016 | ||
|
|
072ae36fe6 | ||
|
|
b5d8b8d258 | ||
|
|
e6b21174f1 | ||
|
|
49094cf999 | ||
|
|
d2c7db6ca0 | ||
|
|
d141f9b973 | ||
|
|
877da8da6d | ||
|
|
8596e63203 | ||
|
|
b2df55e9d7 | ||
|
|
6daf8f8820 | ||
|
|
e75d4fc87d | ||
|
|
9ae07634f2 | ||
|
|
981959ffcf | ||
|
|
dc31321b05 | ||
|
|
64dc3e14ff | ||
|
|
da0893bac0 | ||
|
|
c1747439cd | ||
|
|
f68986827b | ||
|
|
b736b81167 | ||
|
|
0a04b1bb78 | ||
|
|
f7ebaae39e | ||
|
|
08099f0cea | ||
|
|
6fd04dd253 | ||
|
|
9ac97ef91f | ||
|
|
cfbf426174 | ||
|
|
9aafc61c5b | ||
|
|
cd2ebd3046 | ||
|
|
b20e5d7f84 | ||
|
|
13c9a2873e | ||
|
|
fc06283905 | ||
|
|
119d7cadf5 | ||
|
|
cdc6d1fc28 | ||
|
|
49dced2e01 | ||
|
|
76a8f034cb | ||
|
|
52060ac480 | ||
|
|
719532e4df | ||
|
|
70dcc79bf4 | ||
|
|
55b4448862 | ||
|
|
bcaac6f8c1 | ||
|
|
ba4b44db6b | ||
|
|
fd280d0c0b | ||
|
|
1dbf490146 | ||
|
|
62e4df72d3 | ||
|
|
bb77a7c86d | ||
|
|
41abeb85be | ||
|
|
3c86d37148 | ||
|
|
287b38cc87 | ||
|
|
d8d727b1ca | ||
|
|
a81a3d40ce | ||
|
|
52e682489c | ||
|
|
8714ca5a58 | ||
|
|
0490ca163f | ||
|
|
b4947fe8a0 | ||
|
|
9c7b4fddf9 | ||
|
|
5d5b1c2c38 | ||
|
|
cf1aafb121 | ||
|
|
2d4e406a86 | ||
|
|
2a8edd2859 | ||
|
|
a3bc13847c | ||
|
|
944b19ff7c | ||
|
|
f75274bae7 | ||
|
|
62a8a8c57d | ||
|
|
9514f9cd3a | ||
|
|
c1c2725360 | ||
|
|
e9ff26bb1b | ||
|
|
14dc3dfb81 | ||
|
|
44619d5ca2 | ||
|
|
027b7d61ea | ||
|
|
a458ed84f9 | ||
|
|
108f44377d | ||
|
|
dc8439fbfa | ||
|
|
f5353fafa1 | ||
|
|
3d1376bbbc | ||
|
|
b1ea25e86a | ||
|
|
495f6df973 | ||
|
|
a4f1f0841e | ||
|
|
9d0fba81f0 | ||
|
|
92826c6a1e | ||
|
|
7e04be9ec6 | ||
|
|
d954c39ef7 | ||
|
|
176ac5b4fa | ||
|
|
dd696b5cb4 | ||
|
|
501404e403 | ||
|
|
ddf94175ee | ||
|
|
232da9e12b | ||
|
|
8b9ce8eacb | ||
|
|
ee9a4f2526 | ||
|
|
006ce72b2d | ||
|
|
a80bd15bda | ||
|
|
6c63bb2727 | ||
|
|
a7ba93b1d8 | ||
|
|
4a78cd6579 | ||
|
|
b2b8c12203 | ||
|
|
8cc281fad6 | ||
|
|
7346813b8d | ||
|
|
52f3aca22d | ||
|
|
a6a061215f | ||
|
|
7464d8ac8f | ||
|
|
64fda38e2d | ||
|
|
4cefb62d41 | ||
|
|
ccca424234 | ||
|
|
ca45907af0 | ||
|
|
dcf43c7f2b | ||
|
|
1386ec3850 | ||
|
|
de8e16df15 | ||
|
|
222b2d4485 | ||
|
|
e107020bd2 | ||
|
|
430665e984 | ||
|
|
017d5673ba | ||
|
|
f346b9803e | ||
|
|
58092bf66d | ||
|
|
747323efce | ||
|
|
7428e08f93 | ||
|
|
3c8e6d7151 | ||
|
|
43bd2f4cdb | ||
|
|
1dfc9a88a8 | ||
|
|
01beba8697 | ||
|
|
b1e01b238b | ||
|
|
1f595da9ad | ||
|
|
1cf876927d | ||
|
|
a422c935d8 | ||
|
|
1971816663 | ||
|
|
3d1eab872b | ||
|
|
10c1b0c5fa | ||
|
|
4d95cd3630 | ||
|
|
0c169e96e5 | ||
|
|
5baea8400f | ||
|
|
4052cd4fd8 | ||
|
|
21ac400d49 |
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
||||
.github
|
||||
docs
|
||||
examples
|
||||
functions
|
||||
hack
|
||||
site
|
||||
travis
|
||||
*.md
|
||||
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Lint
|
||||
run: ./travis/kyaml-pre-commit.sh
|
||||
run: ./scripts/kyaml-pre-commit.sh
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # don't need to do e2e tests for linting
|
||||
|
||||
|
||||
101
Makefile
101
Makefile
@@ -6,6 +6,17 @@
|
||||
MYGOBIN := $(shell go env GOPATH)/bin
|
||||
SHELL := /bin/bash
|
||||
export PATH := $(MYGOBIN):$(PATH)
|
||||
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
|
||||
|
||||
# Provide defaults for REPO_OWNER and REPO_NAME if not present.
|
||||
# Typically these values would be provided by Prow.
|
||||
ifndef REPO_OWNER
|
||||
REPO_OWNER := "kubernetes-sigs"
|
||||
endif
|
||||
|
||||
ifndef REPO_NAME
|
||||
REPO_NAME := "kustomize"
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: verify-kustomize
|
||||
@@ -15,8 +26,7 @@ verify-kustomize: \
|
||||
lint-kustomize \
|
||||
test-unit-kustomize-all \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-examples-kustomize-against-3.8.0 \
|
||||
test-examples-kustomize-against-3.8.2
|
||||
test-examples-kustomize-against-3.8.6
|
||||
|
||||
# The following target referenced by a file in
|
||||
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
|
||||
@@ -27,8 +37,11 @@ prow-presubmit-check: \
|
||||
test-unit-cmd-all \
|
||||
test-go-mod \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-examples-kustomize-against-3.8.0 \
|
||||
test-examples-kustomize-against-3.8.2
|
||||
test-examples-kustomize-against-3.8.6
|
||||
|
||||
# test-multi-module \
|
||||
# Temporarily removed from prow-presubmit-check
|
||||
# See https://github.com/kubernetes-sigs/kustomize/issues/3191
|
||||
|
||||
.PHONY: verify-kustomize-e2e
|
||||
verify-kustomize-e2e: test-examples-e2e-kustomize
|
||||
@@ -47,35 +60,37 @@ $(MYGOBIN)/golangci-lint-kustomize:
|
||||
GO111MODULE=on go build -tags=tools -o $(MYGOBIN)/golangci-lint-kustomize github.com/golangci/golangci-lint/cmd/golangci-lint; \
|
||||
)
|
||||
|
||||
$(MYGOBIN)/gorepomod:
|
||||
cd api; \
|
||||
go install github.com/monopole/gorepomod
|
||||
|
||||
# Install from version specified in api/go.mod.
|
||||
$(MYGOBIN)/mdrip:
|
||||
cd api; \
|
||||
go install github.com/monopole/mdrip
|
||||
|
||||
# Install from version specified in api/go.mod.
|
||||
$(MYGOBIN)/stringer:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/stringer
|
||||
|
||||
# Install from version specified in api/go.mod.
|
||||
$(MYGOBIN)/goimports:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/goimports
|
||||
|
||||
# Install resource from whatever is checked out.
|
||||
$(MYGOBIN)/resource:
|
||||
cd cmd/resource; \
|
||||
# Build from local source.
|
||||
$(MYGOBIN)/gorepomod:
|
||||
cd cmd/gorepomod; \
|
||||
go install .
|
||||
|
||||
# To pin pluginator, use this recipe instead:
|
||||
# cd api;
|
||||
# go install sigs.k8s.io/kustomize/pluginator/v2
|
||||
# Build from local source.
|
||||
$(MYGOBIN)/pluginator:
|
||||
cd pluginator; \
|
||||
cd cmd/pluginator; \
|
||||
go install .
|
||||
|
||||
# Install kustomize from whatever is checked out.
|
||||
# Build from local source.
|
||||
$(MYGOBIN)/prchecker:
|
||||
cd cmd/prchecker; \
|
||||
go install .
|
||||
|
||||
# Build from local source.
|
||||
$(MYGOBIN)/kustomize:
|
||||
cd kustomize; \
|
||||
go install .
|
||||
@@ -88,7 +103,9 @@ install-tools: \
|
||||
$(MYGOBIN)/gorepomod \
|
||||
$(MYGOBIN)/mdrip \
|
||||
$(MYGOBIN)/pluginator \
|
||||
$(MYGOBIN)/stringer
|
||||
$(MYGOBIN)/prchecker \
|
||||
$(MYGOBIN)/stringer \
|
||||
$(MYGOBIN)/helm
|
||||
|
||||
### Begin kustomize plugin rules.
|
||||
#
|
||||
@@ -130,7 +147,8 @@ _builtinplugins = \
|
||||
PrefixSuffixTransformer.go \
|
||||
ReplicaCountTransformer.go \
|
||||
SecretGenerator.go \
|
||||
ValueAddTransformer.go
|
||||
ValueAddTransformer.go \
|
||||
HelmChartInflationGenerator.go
|
||||
|
||||
# Maintaining this explicit list of generated files, and
|
||||
# adding it as a dependency to a few targets, to assure
|
||||
@@ -156,6 +174,7 @@ $(pGen)/PrefixSuffixTransformer.go: $(pSrc)/prefixsuffixtransformer/PrefixSuffix
|
||||
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
|
||||
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
|
||||
$(pGen)/ValueAddTransformer.go: $(pSrc)/valueaddtransformer/ValueAddTransformer.go
|
||||
$(pGen)/HelmChartInflationGenerator.go: $(pSrc)/helmchartinflationgenerator/HelmChartInflationGenerator.go
|
||||
|
||||
# The (verbose but portable) Makefile way to convert to lowercase.
|
||||
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
|
||||
@@ -190,8 +209,8 @@ lint-kustomize: install-tools $(builtinplugins)
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
||||
cd kustomize; \
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
||||
cd pluginator; \
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
||||
cd cmd/pluginator; \
|
||||
$(MYGOBIN)/golangci-lint-kustomize -c ../../.golangci-kustomize.yml run ./...
|
||||
|
||||
# Used to add non-default compilation flags when experimenting with
|
||||
# plugin-to-api compatibility checks.
|
||||
@@ -218,10 +237,23 @@ test-unit-kustomize-all: \
|
||||
test-unit-kustomize-plugins
|
||||
|
||||
test-unit-cmd-all:
|
||||
./travis/kyaml-pre-commit.sh
|
||||
./scripts/kyaml-pre-commit.sh
|
||||
|
||||
test-go-mod:
|
||||
./travis/check-go-mod.sh
|
||||
./scripts/check-go-mod.sh
|
||||
|
||||
# Environment variables are defined at
|
||||
# https://github.com/kubernetes/test-infra/blob/master/prow/jobs.md#job-environment-variables
|
||||
.PHONY: test-multi-module
|
||||
test-multi-module: $(MYGOBIN)/prchecker
|
||||
( \
|
||||
export MYGOBIN=$(MYGOBIN); \
|
||||
export REPO_OWNER=$(REPO_OWNER); \
|
||||
export REPO_NAME=$(REPO_NAME); \
|
||||
export PULL_NUMBER=$(PULL_NUMBER); \
|
||||
export MODULES=$(MODULES); \
|
||||
./scripts/check-multi-module.sh; \
|
||||
)
|
||||
|
||||
.PHONY:
|
||||
test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
||||
@@ -238,23 +270,10 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
|
||||
./hack/testExamplesAgainstKustomize.sh HEAD
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-3.8.0: $(MYGOBIN)/mdrip
|
||||
test-examples-kustomize-against-3.8.6: $(MYGOBIN)/mdrip
|
||||
( \
|
||||
set -e; \
|
||||
tag=v3.8.0; \
|
||||
/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 .; \
|
||||
)
|
||||
|
||||
.PHONY:
|
||||
test-examples-kustomize-against-3.8.2: $(MYGOBIN)/mdrip
|
||||
( \
|
||||
set -e; \
|
||||
tag=v3.8.2; \
|
||||
tag=v3.8.6; \
|
||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
||||
echo "Installing kustomize $$tag."; \
|
||||
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
|
||||
@@ -301,16 +320,16 @@ $(MYGOBIN)/helmV3:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
tgzFile=helm-v3.2.0-rc.1-linux-amd64.tar.gz; \
|
||||
tgzFile=helm-v3.4.0-linux-amd64.tar.gz; \
|
||||
wget https://get.helm.sh/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv linux-amd64/helm $(MYGOBIN)/helmV3; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
|
||||
# Default version of helm is v2 for the time being.
|
||||
$(MYGOBIN)/helm: $(MYGOBIN)/helmV2
|
||||
ln -s $(MYGOBIN)/helmV2 $(MYGOBIN)/helm
|
||||
# Default version of helm is v3.
|
||||
$(MYGOBIN)/helm: $(MYGOBIN)/helmV3
|
||||
ln -s $(MYGOBIN)/helmV3 $(MYGOBIN)/helm
|
||||
|
||||
$(MYGOBIN)/kind:
|
||||
( \
|
||||
|
||||
178
api/builtins/HelmChartInflationGenerator.go
Normal file
178
api/builtins/HelmChartInflationGenerator.go
Normal file
@@ -0,0 +1,178 @@
|
||||
// Code generated by pluginator on HelmChartInflationGenerator; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// HelmChartInflationGeneratorPlugin is a plugin to generate resources
|
||||
// from a remote or local helm chart.
|
||||
type HelmChartInflationGeneratorPlugin struct {
|
||||
h *resmap.PluginHelpers
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
runHelmCommand func([]string) ([]byte, error)
|
||||
types.HelmChartArgs
|
||||
tmpDir string
|
||||
}
|
||||
|
||||
var KustomizePlugin HelmChartInflationGeneratorPlugin
|
||||
|
||||
// Config uses the input plugin configurations `config` to setup the generator
|
||||
// options
|
||||
func (p *HelmChartInflationGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) error {
|
||||
p.h = h
|
||||
err := yaml.Unmarshal(config, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.tmpDir = string(tmpDir)
|
||||
if p.ChartName == "" {
|
||||
return fmt.Errorf("chartName cannot be empty")
|
||||
}
|
||||
if p.ChartHome == "" {
|
||||
p.ChartHome = path.Join(p.tmpDir, "chart")
|
||||
}
|
||||
if p.ChartRepoName == "" {
|
||||
p.ChartRepoName = "stable"
|
||||
}
|
||||
if p.HelmBin == "" {
|
||||
p.HelmBin = "helm"
|
||||
}
|
||||
if p.HelmHome == "" {
|
||||
p.HelmHome = path.Join(p.tmpDir, ".helm")
|
||||
}
|
||||
if p.Values == "" {
|
||||
p.Values = path.Join(p.ChartHome, p.ChartName, "values.yaml")
|
||||
}
|
||||
// runHelmCommand will run `helm` command with args provided. Return stdout
|
||||
// and error if there is any.
|
||||
p.runHelmCommand = func(args []string) ([]byte, error) {
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd := exec.Command(p.HelmBin, args...)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
cmd.Env = append(cmd.Env,
|
||||
fmt.Sprintf("HELM_CONFIG_HOME=%s", p.HelmHome),
|
||||
fmt.Sprintf("HELM_CACHE_HOME=%s/.cache", p.HelmHome),
|
||||
fmt.Sprintf("HELM_DATA_HOME=%s/.data", p.HelmHome),
|
||||
)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return stdout.Bytes(),
|
||||
errors.Wrap(
|
||||
fmt.Errorf("failed to run command %s %s", p.HelmBin, strings.Join(args, " ")),
|
||||
stderr.String(),
|
||||
)
|
||||
}
|
||||
return stdout.Bytes(), nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate implements generator
|
||||
func (p *HelmChartInflationGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
// cleanup
|
||||
defer os.RemoveAll(p.tmpDir)
|
||||
// check helm version. we only support V3
|
||||
err := p.checkHelmVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// pull the chart
|
||||
if !p.checkLocalChart() {
|
||||
_, err := p.runHelmCommand(p.getPullCommandArgs())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// render the charts
|
||||
stdout, err := p.runHelmCommand(p.getTemplateCommandArgs())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.h.ResmapFactory().NewResMapFromBytes(stdout)
|
||||
}
|
||||
|
||||
func (p *HelmChartInflationGeneratorPlugin) getTemplateCommandArgs() []string {
|
||||
args := []string{"template"}
|
||||
if p.ReleaseName != "" {
|
||||
args = append(args, p.ReleaseName)
|
||||
}
|
||||
args = append(args, path.Join(p.ChartHome, p.ChartName))
|
||||
if p.ReleaseNamespace != "" {
|
||||
args = append(args, "--namespace", p.ReleaseNamespace)
|
||||
}
|
||||
if p.Values != "" {
|
||||
args = append(args, "--values", p.Values)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func (p *HelmChartInflationGeneratorPlugin) getPullCommandArgs() []string {
|
||||
args := []string{"pull", "--untar", "--untardir", p.ChartHome}
|
||||
chartName := fmt.Sprintf("%s/%s", p.ChartRepoName, p.ChartName)
|
||||
if p.ChartVersion != "" {
|
||||
args = append(args, "--version", p.ChartVersion)
|
||||
}
|
||||
if p.ChartRepoURL != "" {
|
||||
args = append(args, "--repo", p.ChartRepoURL)
|
||||
chartName = p.ChartName
|
||||
}
|
||||
|
||||
args = append(args, chartName)
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// checkLocalChart will return true if the chart does exist in
|
||||
// local chart home.
|
||||
func (p *HelmChartInflationGeneratorPlugin) checkLocalChart() bool {
|
||||
path := path.Join(p.ChartHome, p.ChartName)
|
||||
s, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return s.IsDir()
|
||||
}
|
||||
|
||||
// checkHelmVersion will return an error if the helm version is not V3
|
||||
func (p *HelmChartInflationGeneratorPlugin) checkHelmVersion() error {
|
||||
stdout, err := p.runHelmCommand([]string{"version", "-c", "--short"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := regexp.Compile(`v\d+(\.\d+)+`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := string(r.Find(stdout))[1:]
|
||||
majorVersion := strings.Split(v, ".")[0]
|
||||
if majorVersion != "3" {
|
||||
return fmt.Errorf("this plugin requires helm V3 but got v%s", v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHelmChartInflationGeneratorPlugin() resmap.GeneratorPlugin {
|
||||
return &HelmChartInflationGeneratorPlugin{}
|
||||
}
|
||||
@@ -7,9 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -53,74 +51,6 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special casing metadata.namespace since
|
||||
// all objects have it, even "ClusterKind" objects
|
||||
// that don't exist in a namespace (the Namespace
|
||||
// object itself doesn't live in a namespace).
|
||||
func (p *NamespaceTransformerPlugin) applicableFieldSpecs(id resid.ResId) []types.FieldSpec {
|
||||
var res []types.FieldSpec
|
||||
for _, fs := range p.FieldSpecs {
|
||||
if id.IsSelected(&fs.Gvk) &&
|
||||
(fs.Path != types.MetadataNamespacePath ||
|
||||
(fs.Path == types.MetadataNamespacePath && id.IsNamespaceableKind())) {
|
||||
res = append(res, fs)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) changeNamespace(
|
||||
_ *resource.Resource) func(in interface{}) (interface{}, error) {
|
||||
return func(in interface{}) (interface{}, error) {
|
||||
switch in.(type) {
|
||||
case string:
|
||||
// will happen when the metadata/namespace
|
||||
// value is replaced
|
||||
return p.Namespace, nil
|
||||
case []interface{}:
|
||||
l, _ := in.([]interface{})
|
||||
for idx, item := range l {
|
||||
switch item.(type) {
|
||||
case map[string]interface{}:
|
||||
// Will happen when mutating the subjects
|
||||
// field of ClusterRoleBinding and RoleBinding
|
||||
inMap, _ := item.(map[string]interface{})
|
||||
if _, ok := inMap["name"]; !ok {
|
||||
continue
|
||||
}
|
||||
name, ok := inMap["name"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// The only case we need to force the namespace
|
||||
// if for the "service account". "default" is
|
||||
// kind of hardcoded here for right now.
|
||||
if name != "default" {
|
||||
continue
|
||||
}
|
||||
inMap["namespace"] = p.Namespace
|
||||
l[idx] = inMap
|
||||
default:
|
||||
// nothing to do for right now
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
case map[string]interface{}:
|
||||
// Will happen if the createField=true
|
||||
// when the namespace is added to the
|
||||
// object
|
||||
inMap := in.(map[string]interface{})
|
||||
if len(inMap) == 0 {
|
||||
return p.Namespace, nil
|
||||
} else {
|
||||
return in, nil
|
||||
}
|
||||
default:
|
||||
return in, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &NamespaceTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
@@ -20,9 +19,9 @@ import (
|
||||
type PatchJson6902TransformerPlugin struct {
|
||||
ldr ifc.Loader
|
||||
decodedPatch jsonpatch.Patch
|
||||
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PatchJson6902TransformerPlugin) Config(
|
||||
@@ -72,22 +71,22 @@ func (p *PatchJson6902TransformerPlugin) Config(
|
||||
}
|
||||
|
||||
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
id := resid.NewResIdWithNamespace(
|
||||
resid.Gvk{
|
||||
Group: p.Target.Group,
|
||||
Version: p.Target.Version,
|
||||
Kind: p.Target.Kind,
|
||||
},
|
||||
p.Target.Name,
|
||||
p.Target.Namespace,
|
||||
)
|
||||
obj, err := m.GetById(id)
|
||||
if p.Target == nil {
|
||||
return fmt.Errorf("must specify a target for patch %s", p.JsonOp)
|
||||
}
|
||||
resources, err := m.Select(*p.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return filtersutil.ApplyToJSON(patchjson6902.Filter{
|
||||
Patch: p.JsonOp,
|
||||
}, obj)
|
||||
for _, res := range resources {
|
||||
err = filtersutil.ApplyToJSON(patchjson6902.Filter{
|
||||
Patch: p.JsonOp,
|
||||
}, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package nameref
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
@@ -9,6 +11,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
kyaml_filtersutil "sigs.k8s.io/kustomize/kyaml/filtersutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -19,6 +22,7 @@ type Filter struct {
|
||||
Referrer *resource.Resource
|
||||
Target resid.Gvk
|
||||
ReferralCandidates resmap.ResMap
|
||||
isRoleRef bool
|
||||
}
|
||||
|
||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
@@ -37,6 +41,9 @@ func (f Filter) set(node *yaml.RNode) error {
|
||||
if yaml.IsMissingOrNull(node) {
|
||||
return nil
|
||||
}
|
||||
if strings.HasSuffix(f.FieldSpec.Path, "roleRef/name") {
|
||||
f.isRoleRef = true
|
||||
}
|
||||
switch node.YNode().Kind {
|
||||
case yaml.ScalarNode:
|
||||
return f.setScalar(node)
|
||||
@@ -65,6 +72,7 @@ func (f Filter) setMapping(node *yaml.RNode) error {
|
||||
f.Referrer,
|
||||
f.Target,
|
||||
f.ReferralCandidates,
|
||||
f.isRoleRef,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,6 +83,7 @@ func (f Filter) setScalar(node *yaml.RNode) error {
|
||||
f.Target,
|
||||
f.ReferralCandidates,
|
||||
f.ReferralCandidates.Resources(),
|
||||
f.isRoleRef,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -86,6 +95,40 @@ func (f Filter) setScalar(node *yaml.RNode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getRoleRefGvk returns a Gvk in the roleRef field. Return error
|
||||
// if the roleRef, roleRef/apiGroup or roleRef/kind is missing.
|
||||
func getRoleRefGvk(res json.Marshaler) (*resid.Gvk, error) {
|
||||
n, err := kyaml_filtersutil.GetRNode(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roleRef, err := n.Pipe(yaml.Lookup("roleRef"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if roleRef.IsNil() {
|
||||
return nil, fmt.Errorf("roleRef cannot be found in %s", n.MustString())
|
||||
}
|
||||
apiGroup, err := roleRef.Pipe(yaml.Lookup("apiGroup"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if apiGroup.IsNil() {
|
||||
return nil, fmt.Errorf("apiGroup cannot be found in roleRef %s", roleRef.MustString())
|
||||
}
|
||||
kind, err := roleRef.Pipe(yaml.Lookup("kind"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if kind.IsNil() {
|
||||
return nil, fmt.Errorf("kind cannot be found in roleRef %s", roleRef.MustString())
|
||||
}
|
||||
return &resid.Gvk{
|
||||
Group: apiGroup.YNode().Value,
|
||||
Kind: kind.YNode().Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func filterReferralCandidates(
|
||||
referrer *resource.Resource,
|
||||
matches []*resource.Resource,
|
||||
@@ -117,11 +160,22 @@ func selectReferral(
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap,
|
||||
referralCandidateSubset []*resource.Resource) (string, string, error) {
|
||||
|
||||
referralCandidateSubset []*resource.Resource,
|
||||
isRoleRef bool) (string, string, error) {
|
||||
var roleRefGvk *resid.Gvk
|
||||
if isRoleRef {
|
||||
var err error
|
||||
roleRefGvk, err = getRoleRefGvk(referrer)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
for _, res := range referralCandidateSubset {
|
||||
id := res.OrgId()
|
||||
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
||||
// If the we are processing a roleRef, the apiGroup and Kind in the
|
||||
// roleRef are needed to be considered.
|
||||
if (!isRoleRef || id.IsSelected(roleRefGvk)) &&
|
||||
id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
||||
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
|
||||
// If there's more than one match,
|
||||
// filter the matches by prefix and suffix
|
||||
@@ -155,10 +209,11 @@ func getSimpleNameField(
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap,
|
||||
referralCandidateSubset []*resource.Resource) (string, error) {
|
||||
referralCandidateSubset []*resource.Resource,
|
||||
isRoleRef bool) (string, error) {
|
||||
|
||||
newName, _, err := selectReferral(oldName, referrer, target,
|
||||
referralCandidates, referralCandidateSubset)
|
||||
referralCandidates, referralCandidateSubset, isRoleRef)
|
||||
|
||||
return newName, err
|
||||
}
|
||||
@@ -177,7 +232,8 @@ func setNameAndNs(
|
||||
in *yaml.RNode,
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap) error {
|
||||
referralCandidates resmap.ResMap,
|
||||
isRoleRef bool) error {
|
||||
|
||||
if in.YNode().Kind != yaml.MappingNode {
|
||||
return fmt.Errorf("expect a mapping node")
|
||||
@@ -213,7 +269,7 @@ func setNameAndNs(
|
||||
|
||||
oldName := nameNode.YNode().Value
|
||||
newname, newnamespace, err := selectReferral(oldName, referrer, target,
|
||||
referralCandidates, subset)
|
||||
referralCandidates, subset, isRoleRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -194,47 +194,47 @@ metadata:
|
||||
{
|
||||
name: "update-clusterrolebinding",
|
||||
input: `
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
namespace: foo
|
||||
`,
|
||||
expected: `
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: default
|
||||
namespace: bar
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
---
|
||||
apiVersion: example.com/v1
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
subjects:
|
||||
- name: something
|
||||
|
||||
@@ -370,6 +370,213 @@ spec:
|
||||
image: test2
|
||||
- name: test
|
||||
image: test
|
||||
`,
|
||||
},
|
||||
"list map keys - add a port, no names": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
`,
|
||||
patch: yaml.MustParse(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
- containerPort: 80
|
||||
protocol: UDP
|
||||
`),
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
- containerPort: 80
|
||||
protocol: UDP
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
`,
|
||||
},
|
||||
"list map keys - add name to port": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
`,
|
||||
patch: yaml.MustParse(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
name: UDP-name-patch
|
||||
`),
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
name: UDP-name-patch
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
`,
|
||||
},
|
||||
"list map keys - replace port name": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
name: UDP-name-original
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
name: TCP-name-original
|
||||
`,
|
||||
patch: yaml.MustParse(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
name: UDP-name-patch
|
||||
`),
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: UDP
|
||||
name: UDP-name-patch
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
name: TCP-name-original
|
||||
`,
|
||||
},
|
||||
"list map keys - add a port, no protocol": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
`,
|
||||
patch: yaml.MustParse(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 80
|
||||
`),
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: test-image
|
||||
name: test-deployment
|
||||
ports:
|
||||
- containerPort: 80
|
||||
- containerPort: 8080
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ require (
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/go-openapi/spec v0.19.5
|
||||
github.com/golangci/golangci-lint v1.21.0
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/yujunz/go-getter v1.4.1-lite
|
||||
@@ -17,6 +19,6 @@ require (
|
||||
k8s.io/apimachinery v0.17.0
|
||||
k8s.io/client-go v0.17.0
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
@@ -232,8 +232,12 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
@@ -588,8 +592,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/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1 h1:T7aNUraSioQp0NHJZtYjIhL/q8mqRzCiHcAKdvo09go=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4 h1:DDuzZtjIzFqp2IPy4DTyCI69Cl3bDgcJODjI6sjF9NY=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
|
||||
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.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
|
||||
@@ -789,9 +789,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
|
||||
"name": modifiedname,
|
||||
},
|
||||
"roleRef": map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRole",
|
||||
"name": orgname,
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": orgname,
|
||||
},
|
||||
"subjects": []interface{}{
|
||||
map[string]interface{}{
|
||||
@@ -845,9 +845,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
|
||||
"name": modifiedname,
|
||||
},
|
||||
"roleRef": map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRole",
|
||||
"name": modifiedname,
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": modifiedname,
|
||||
},
|
||||
// The following tests required a change in
|
||||
// getNameFunc implementation in order to leverage
|
||||
@@ -937,9 +937,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
|
||||
"name": modifiedname,
|
||||
},
|
||||
"roleRef": map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRole",
|
||||
"name": orgname,
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": orgname,
|
||||
},
|
||||
"subjects": []interface{}{
|
||||
map[string]interface{}{
|
||||
@@ -973,9 +973,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
|
||||
"name": modifiedname,
|
||||
},
|
||||
"roleRef": map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRole",
|
||||
"name": modifiedname,
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": modifiedname,
|
||||
},
|
||||
// The following tests required a change in
|
||||
// getNameFunc implementation in order to leverage
|
||||
|
||||
@@ -206,8 +206,10 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:Fecb
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
@@ -527,8 +529,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/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=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1 h1:T7aNUraSioQp0NHJZtYjIhL/q8mqRzCiHcAKdvo09go=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4 h1:DDuzZtjIzFqp2IPy4DTyCI69Cl3bDgcJODjI6sjF9NY=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
|
||||
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/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
||||
@@ -23,11 +23,12 @@ func _() {
|
||||
_ = x[ReplicaCountTransformer-12]
|
||||
_ = x[SecretGenerator-13]
|
||||
_ = x[ValueAddTransformer-14]
|
||||
_ = x[HelmChartInflationGenerator-15]
|
||||
}
|
||||
|
||||
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformer"
|
||||
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformerHelmChartInflationGenerator"
|
||||
|
||||
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 97, 119, 139, 163, 193, 209, 232, 255, 270, 289}
|
||||
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 97, 119, 139, 163, 193, 209, 232, 255, 270, 289, 316}
|
||||
|
||||
func (i BuiltinPluginType) String() string {
|
||||
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {
|
||||
|
||||
@@ -27,6 +27,7 @@ const (
|
||||
ReplicaCountTransformer
|
||||
SecretGenerator
|
||||
ValueAddTransformer
|
||||
HelmChartInflationGenerator
|
||||
)
|
||||
|
||||
var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType
|
||||
@@ -55,8 +56,9 @@ func GetBuiltinPluginType(n string) BuiltinPluginType {
|
||||
}
|
||||
|
||||
var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{
|
||||
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
|
||||
SecretGenerator: builtins.NewSecretGeneratorPlugin,
|
||||
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
|
||||
SecretGenerator: builtins.NewSecretGeneratorPlugin,
|
||||
HelmChartInflationGenerator: builtins.NewHelmChartInflationGeneratorPlugin,
|
||||
}
|
||||
|
||||
var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin{
|
||||
|
||||
@@ -94,7 +94,7 @@ TO GENERATE CODE
|
||||
cd $repo/plugin/builtin
|
||||
go generate ./...
|
||||
|
||||
See travis/kyaml-pre-commit.sh for canonical way
|
||||
See scripts/kyaml-pre-commit.sh for canonical way
|
||||
to execute the above.
|
||||
|
||||
This creates
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/builtins"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
@@ -313,12 +314,18 @@ func (kt *KustTarget) accumulateResources(
|
||||
if errF := kt.accumulateFile(ra, path); errF != nil {
|
||||
ldr, errL := kt.ldr.New(path)
|
||||
if errL != nil {
|
||||
return nil, fmt.Errorf("accumulateFile %q, loader.New %q", errF, errL)
|
||||
return nil, multierror.Append(
|
||||
fmt.Errorf("accumulateFile error: %q", errF),
|
||||
fmt.Errorf("loader.New error: %q", errL),
|
||||
)
|
||||
}
|
||||
var errD error
|
||||
ra, errD = kt.accumulateDirectory(ra, ldr, false)
|
||||
if errD != nil {
|
||||
return nil, fmt.Errorf("accumulateFile %q, accumulateDirector: %q", errF, errD)
|
||||
return nil, multierror.Append(
|
||||
fmt.Errorf("accumulateFile error: %q", errF),
|
||||
fmt.Errorf("accumulateDirector error: %q", errD),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ func (kt *KustTarget) configureBuiltinGenerators() (
|
||||
for _, bpt := range []builtinhelpers.BuiltinPluginType{
|
||||
builtinhelpers.ConfigMapGenerator,
|
||||
builtinhelpers.SecretGenerator,
|
||||
builtinhelpers.HelmChartInflationGenerator,
|
||||
} {
|
||||
r, err := generatorConfigurators[bpt](
|
||||
kt, bpt, builtinhelpers.GeneratorFactories[bpt])
|
||||
@@ -110,6 +111,23 @@ var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
}
|
||||
return
|
||||
},
|
||||
|
||||
builtinhelpers.HelmChartInflationGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.HelmChartArgs
|
||||
}
|
||||
for _, args := range kt.kustomization.HelmChartInflationGenerator {
|
||||
c.HelmChartArgs = args
|
||||
p := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
type tFactory func() resmap.TransformerPlugin
|
||||
@@ -141,12 +159,12 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||
c.Target = *args.Target
|
||||
c.Target = args.Target
|
||||
c.Path = args.Path
|
||||
c.JsonOp = args.Patch
|
||||
p := f()
|
||||
|
||||
@@ -26,13 +26,15 @@ func newMultiTransformer(t []resmap.Transformer) resmap.Transformer {
|
||||
return r
|
||||
}
|
||||
|
||||
// Transform prepends the name prefix.
|
||||
// Transform applies the member transformers in order to the resources,
|
||||
// optionally detecting and erroring on commutation conflict.
|
||||
func (o *multiTransformer) Transform(m resmap.ResMap) error {
|
||||
if o.checkConflictEnabled {
|
||||
return o.transformWithCheckConflict(m)
|
||||
}
|
||||
return o.transform(m)
|
||||
}
|
||||
|
||||
func (o *multiTransformer) transform(m resmap.ResMap) error {
|
||||
for _, t := range o.transformers {
|
||||
err := t.Transform(m)
|
||||
|
||||
@@ -21,5 +21,5 @@ import (
|
||||
// major version increments in pluginator with each
|
||||
// api release to allow this trick to work and not
|
||||
// introduce cycles.
|
||||
// _ "sigs.k8s.io/kustomize/pluginator/v2"
|
||||
// _ "sigs.k8s.io/kustomize/cmd/pluginator/v2"
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wrappy_test
|
||||
package wrappy
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
package wrappy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
@@ -54,10 +56,41 @@ func (wn *WNode) GetAnnotations() map[string]string {
|
||||
|
||||
// GetFieldValue implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetFieldValue(path string) (interface{}, error) {
|
||||
// The argument is a json path, e.g. "metadata.name"
|
||||
// fields := strings.Split(path, ".")
|
||||
// return wn.node.Pipe(yaml.Lookup(fields...))
|
||||
panic("TODO(#WNode): GetFieldValue; implement or drop from API")
|
||||
fields := strings.Split(path, ".")
|
||||
rn, err := wn.node.Pipe(yaml.Lookup(fields...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rn == nil {
|
||||
return nil, NoFieldError{path}
|
||||
}
|
||||
yn := rn.YNode()
|
||||
|
||||
// If this is an alias node, resolve it
|
||||
if yn.Kind == yaml.AliasNode {
|
||||
yn = yn.Alias
|
||||
}
|
||||
|
||||
// Return value as map for DocumentNode and MappingNode kinds
|
||||
if yn.Kind == yaml.DocumentNode || yn.Kind == yaml.MappingNode {
|
||||
var result map[string]interface{}
|
||||
if err := yn.Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Return value as slice for SequenceNode kind
|
||||
if yn.Kind == yaml.SequenceNode {
|
||||
var result []interface{}
|
||||
for _, node := range yn.Content {
|
||||
result = append(result, node.Value)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Return value value directly for all other (ScalarNode) kinds
|
||||
return yn.Value, nil
|
||||
}
|
||||
|
||||
// GetGvk implements ifc.Kunstructured.
|
||||
@@ -83,18 +116,37 @@ func (wn *WNode) GetName() string {
|
||||
}
|
||||
|
||||
// GetSlice implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetSlice(string) ([]interface{}, error) {
|
||||
panic("TODO(#WNode) GetSlice; implement or drop from API")
|
||||
func (wn *WNode) GetSlice(path string) ([]interface{}, error) {
|
||||
value, err := wn.GetFieldValue(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sliceValue, ok := value.([]interface{}); ok {
|
||||
return sliceValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf("node %s is not a slice", path)
|
||||
}
|
||||
|
||||
// GetSlice implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetString(string) (string, error) {
|
||||
panic("TODO(#WNode) GetString; implement or drop from API")
|
||||
func (wn *WNode) GetString(path string) (string, error) {
|
||||
value, err := wn.GetFieldValue(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if v, ok := value.(string); ok {
|
||||
return v, nil
|
||||
}
|
||||
return "", fmt.Errorf("node %s is not a string: %v", path, value)
|
||||
}
|
||||
|
||||
// Map implements ifc.Kunstructured.
|
||||
func (wn *WNode) Map() map[string]interface{} {
|
||||
panic("TODO(#WNode) Map; implement or drop from API")
|
||||
var result map[string]interface{}
|
||||
if err := wn.node.YNode().Decode(&result); err != nil {
|
||||
// Log and die since interface doesn't allow error.
|
||||
log.Fatalf("failed to decode ynode: %v", err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// MarshalJSON implements ifc.Kunstructured.
|
||||
@@ -113,31 +165,51 @@ func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
|
||||
}
|
||||
|
||||
// SetAnnotations implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetAnnotations(map[string]string) {
|
||||
panic("TODO(#WNode) SetAnnotations; implement or drop from API")
|
||||
func (wn *WNode) SetAnnotations(annotations map[string]string) {
|
||||
wn.setField(yaml.NewMapRNode(&annotations), yaml.MetadataField, yaml.AnnotationsField)
|
||||
}
|
||||
|
||||
// SetGvk implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetGvk(resid.Gvk) {
|
||||
panic("TODO(#WNode) SetGvk; implement or drop from API")
|
||||
func (wn *WNode) SetGvk(gvk resid.Gvk) {
|
||||
wn.setField(yaml.NewScalarRNode(gvk.Kind), yaml.KindField)
|
||||
wn.setField(yaml.NewScalarRNode(fmt.Sprintf("%s/%s", gvk.Group, gvk.Version)), yaml.APIVersionField)
|
||||
}
|
||||
|
||||
// SetLabels implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetLabels(map[string]string) {
|
||||
panic("TODO(#WNode) SetLabels; implement or drop from API")
|
||||
func (wn *WNode) SetLabels(labels map[string]string) {
|
||||
wn.setField(yaml.NewMapRNode(&labels), yaml.MetadataField, yaml.LabelsField)
|
||||
}
|
||||
|
||||
// SetName implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetName(string) {
|
||||
panic("TODO(#WNode) SetName; implement or drop from API")
|
||||
func (wn *WNode) SetName(name string) {
|
||||
wn.setField(yaml.NewScalarRNode(name), yaml.MetadataField, yaml.NameField)
|
||||
}
|
||||
|
||||
// SetNamespace implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetNamespace(string) {
|
||||
panic("TODO(#WNode) SetNamespace; implement or drop from API")
|
||||
func (wn *WNode) SetNamespace(ns string) {
|
||||
wn.setField(yaml.NewScalarRNode(ns), yaml.MetadataField, yaml.NamespaceField)
|
||||
}
|
||||
|
||||
func (wn *WNode) setField(value *yaml.RNode, path ...string) {
|
||||
err := wn.node.PipeE(
|
||||
yaml.LookupCreate(yaml.MappingNode, path[0:len(path)-1]...),
|
||||
yaml.SetField(path[len(path)-1], value),
|
||||
)
|
||||
if err != nil {
|
||||
// Log and die since interface doesn't allow error.
|
||||
log.Fatalf("failed to set field %v: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements ifc.Kunstructured.
|
||||
func (wn *WNode) UnmarshalJSON(data []byte) error {
|
||||
return wn.node.UnmarshalJSON(data)
|
||||
}
|
||||
|
||||
type NoFieldError struct {
|
||||
Field string
|
||||
}
|
||||
|
||||
func (e NoFieldError) Error() string {
|
||||
return fmt.Sprintf("no field named '%s'", e.Field)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wrappy_test
|
||||
package wrappy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
. "sigs.k8s.io/kustomize/api/internal/wrappy"
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
@@ -337,3 +339,215 @@ func TestGettingFields(t *testing.T) {
|
||||
t.Fatalf("unexpected annotations '%v'", actualMap)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFieldValueReturnsMap(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
expected := map[string]interface{}{
|
||||
"fruit": "apple",
|
||||
"veggie": "carrot",
|
||||
}
|
||||
actual, err := wn.GetFieldValue("metadata.labels")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting field value: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, actual); diff != "" {
|
||||
t.Fatalf("actual map does not deep equal expected map:\n%v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFieldValueReturnsSlice(t *testing.T) {
|
||||
bytes, err := yaml.Marshal(makeBigMap())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml.Marshal err: %v", err)
|
||||
}
|
||||
rNode, err := kyaml.Parse(string(bytes))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml.Marshal err: %v", err)
|
||||
}
|
||||
wn := FromRNode(rNode)
|
||||
expected := []interface{}{"idx0", "idx1", "idx2", "idx3"}
|
||||
actual, err := wn.GetFieldValue("that")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting slice: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, actual); diff != "" {
|
||||
t.Fatalf("actual slice does not deep equal expected slice:\n%v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFieldValueReturnsString(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
actual, err := wn.GetFieldValue("metadata.labels.fruit")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting field value: %v", err)
|
||||
}
|
||||
v, ok := actual.(string)
|
||||
if !ok || v != "apple" {
|
||||
t.Fatalf("unexpected value '%v'", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFieldValueResolvesAlias(t *testing.T) {
|
||||
yamlWithAlias := `
|
||||
foo: &a theValue
|
||||
bar: *a
|
||||
`
|
||||
rNode, err := kyaml.Parse(yamlWithAlias)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml parse error: %v", err)
|
||||
}
|
||||
wn := FromRNode(rNode)
|
||||
actual, err := wn.GetFieldValue("bar")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting field value: %v", err)
|
||||
}
|
||||
v, ok := actual.(string)
|
||||
if !ok || v != "theValue" {
|
||||
t.Fatalf("unexpected value '%v'", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetString(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
expected := "carrot"
|
||||
actual, err := wn.GetString("metadata.labels.veggie")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting string: %v", err)
|
||||
}
|
||||
if expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSlice(t *testing.T) {
|
||||
bytes, err := yaml.Marshal(makeBigMap())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml.Marshal err: %v", err)
|
||||
}
|
||||
rNode, err := kyaml.Parse(string(bytes))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml.Marshal err: %v", err)
|
||||
}
|
||||
wn := FromRNode(rNode)
|
||||
expected := []interface{}{"idx0", "idx1", "idx2", "idx3"}
|
||||
actual, err := wn.GetSlice("that")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting slice: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(expected, actual); diff != "" {
|
||||
t.Fatalf("actual slice does not deep equal expected slice:\n%v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentLittleJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
|
||||
expected := map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "homer",
|
||||
"namespace": "simpsons",
|
||||
},
|
||||
}
|
||||
|
||||
actual := wn.Map()
|
||||
if diff := cmp.Diff(expected, actual); diff != "" {
|
||||
t.Fatalf("actual map does not deep equal expected map:\n%v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetName(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
wn.SetName("marge")
|
||||
if expected, actual := "marge", wn.GetName(); expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetNamespace(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
wn.SetNamespace("flanders")
|
||||
meta, _ := wn.node.GetMeta()
|
||||
if expected, actual := "flanders", meta.Namespace; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetLabels(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
wn.SetLabels(map[string]string{
|
||||
"label1": "foo",
|
||||
"label2": "bar",
|
||||
})
|
||||
labels := wn.GetLabels()
|
||||
if expected, actual := 2, len(labels); expected != actual {
|
||||
t.Fatalf("expected '%d', got '%d'", expected, actual)
|
||||
}
|
||||
if expected, actual := "foo", labels["label1"]; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
if expected, actual := "bar", labels["label2"]; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAnnotations(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
wn.SetAnnotations(map[string]string{
|
||||
"annotation1": "foo",
|
||||
"annotation2": "bar",
|
||||
})
|
||||
annotations := wn.GetAnnotations()
|
||||
if expected, actual := 2, len(annotations); expected != actual {
|
||||
t.Fatalf("expected '%d', got '%d'", expected, actual)
|
||||
}
|
||||
if expected, actual := "foo", annotations["annotation1"]; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
if expected, actual := "bar", annotations["annotation2"]; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGvk(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
wn.SetGvk(resid.GvkFromString("grp_ver_knd"))
|
||||
gvk := wn.GetGvk()
|
||||
if expected, actual := "grp", gvk.Group; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
if expected, actual := "ver", gvk.Version; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
if expected, actual := "knd", gvk.Kind; expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +238,8 @@ nameReference:
|
||||
kind: Ingress
|
||||
- path: metadata/annotations/nginx.ingress.kubernetes.io\/auth-tls-secret
|
||||
kind: Ingress
|
||||
- path: spec/tls/secretName
|
||||
kind: Ingress
|
||||
- path: imagePullSecrets/name
|
||||
kind: ServiceAccount
|
||||
- path: parameters/secretName
|
||||
@@ -267,6 +269,10 @@ nameReference:
|
||||
kind: Ingress
|
||||
- path: spec/backend/serviceName
|
||||
kind: Ingress
|
||||
- path: spec/rules/http/paths/backend/service/name
|
||||
kind: Ingress
|
||||
- path: spec/defaultBackend/service/name
|
||||
kind: Ingress
|
||||
- path: spec/service/name
|
||||
kind: APIService
|
||||
group: apiregistration.k8s.io
|
||||
@@ -373,5 +379,12 @@ nameReference:
|
||||
kind: Job
|
||||
- path: spec/template/spec/priorityClassName
|
||||
kind: DaemonSet
|
||||
|
||||
- kind: IngressClass
|
||||
version: v1
|
||||
group: networking.k8s.io/v1
|
||||
fieldSpecs:
|
||||
- path: spec/ingressClassName
|
||||
kind: Ingress
|
||||
`
|
||||
)
|
||||
|
||||
103
api/krusty/helmchartinflationgenerator_test.go
Normal file
103
api/krusty/helmchartinflationgenerator_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
/*
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
var expected string = `
|
||||
apiVersion: v1
|
||||
data:
|
||||
rcon-password: Q0hBTkdFTUUh
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
app: test-minecraft
|
||||
chart: minecraft-1.2.0
|
||||
heritage: Helm
|
||||
release: test
|
||||
name: test-minecraft
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
annotations:
|
||||
volume.alpha.kubernetes.io/storage-class: default
|
||||
labels:
|
||||
app: test-minecraft
|
||||
chart: minecraft-1.2.0
|
||||
heritage: Helm
|
||||
release: test
|
||||
name: test-minecraft-datadir
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: test-minecraft
|
||||
chart: minecraft-1.2.0
|
||||
heritage: Helm
|
||||
release: test
|
||||
name: test-minecraft
|
||||
spec:
|
||||
ports:
|
||||
- name: minecraft
|
||||
port: 25565
|
||||
protocol: TCP
|
||||
targetPort: minecraft
|
||||
selector:
|
||||
app: test-minecraft
|
||||
type: LoadBalancer
|
||||
`
|
||||
|
||||
func TestHelmChartInflationGenerator(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app", `
|
||||
helmChartInflationGenerator:
|
||||
- chartName: minecraft
|
||||
chartRepoUrl: https://kubernetes-charts.storage.googleapis.com
|
||||
chartVersion: v1.2.0
|
||||
releaseName: test
|
||||
releaseNamespace: testNamespace
|
||||
`)
|
||||
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, expected)
|
||||
}
|
||||
|
||||
|
||||
func TestHelmChartInflationGeneratorAsPlugin(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/app", `
|
||||
generators:
|
||||
- helm.yaml
|
||||
`)
|
||||
|
||||
th.WriteF("/app/helm.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: HelmChartInflationGenerator
|
||||
metadata:
|
||||
name: myMap
|
||||
chartName: minecraft
|
||||
chartRepoUrl: https://kubernetes-charts.storage.googleapis.com
|
||||
chartVersion: v1.2.0
|
||||
releaseName: test
|
||||
releaseNamespace: testNamespace
|
||||
`)
|
||||
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, expected)
|
||||
}
|
||||
*/
|
||||
@@ -159,7 +159,7 @@ subjects:
|
||||
name: default
|
||||
namespace: irrelevant
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: example
|
||||
@@ -180,15 +180,17 @@ webhooks:
|
||||
name: svc3
|
||||
namespace: random
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: crds.my.org
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: cr1
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: crb1
|
||||
@@ -197,6 +199,7 @@ subjects:
|
||||
name: default
|
||||
namespace: irrelevant
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: pv1
|
||||
@@ -257,7 +260,7 @@ subjects:
|
||||
name: default
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: p1-example-s1
|
||||
@@ -278,15 +281,17 @@ webhooks:
|
||||
namespace: random
|
||||
name: example3
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: crds.my.org
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: p1-cr1-s1
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: p1-crb1-s1
|
||||
@@ -295,6 +300,7 @@ subjects:
|
||||
name: default
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: p1-pv1-s1
|
||||
|
||||
287
api/krusty/nameupdateinroleref_test.go
Normal file
287
api/krusty/nameupdateinroleref_test.go
Normal file
@@ -0,0 +1,287 @@
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// https://github.com/kubernetes-sigs/kustomize/issues/2640
|
||||
func TestNameUpdateInRoleRef(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("/app/rbac.yaml", `
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: my-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: my-role
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: my-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: my-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: my-role
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
version: v1
|
||||
kind: Role
|
||||
name: my-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
`)
|
||||
|
||||
th.WriteK("/app", `
|
||||
namespace: foo
|
||||
resources:
|
||||
- rbac.yaml
|
||||
|
||||
patches:
|
||||
- patch: |-
|
||||
- op: add
|
||||
path: /metadata/name
|
||||
value: prefix_my-role
|
||||
target:
|
||||
group: rbac.authorization.k8s.io
|
||||
version: v1
|
||||
kind: ClusterRole
|
||||
name: my-role
|
||||
`)
|
||||
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: prefix_my-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: my-role
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: prefix_my-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: my-role
|
||||
namespace: foo
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: my-role
|
||||
namespace: foo
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: my-role
|
||||
version: v1
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: foo
|
||||
`)
|
||||
}
|
||||
|
||||
// https://github.com/kubernetes-sigs/kustomize/issues/3073
|
||||
func TestNameUpdateInRoleRef2(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("/app/workloads.yaml", `
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: myapp
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: myapp
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes/metrics
|
||||
verbs:
|
||||
- get
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: myapp
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: myapp
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: myapp
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myapp
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
verbs:
|
||||
- get
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: myapp
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: myapp
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: myapp
|
||||
`)
|
||||
|
||||
th.WriteF("/app/suffixTransformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PrefixSuffixTransformer
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
suffix: -suffix
|
||||
fieldSpecs:
|
||||
- path: metadata/name
|
||||
kind: ClusterRole
|
||||
name: myapp
|
||||
- path: metadata/name
|
||||
kind: ClusterRoleBinding
|
||||
name: myapp
|
||||
`)
|
||||
|
||||
th.WriteK("/app", `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- workloads.yaml
|
||||
transformers:
|
||||
- suffixTransformer.yaml
|
||||
namespace: test
|
||||
|
||||
`)
|
||||
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: myapp
|
||||
namespace: test
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: myapp-suffix
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes/metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: myapp-suffix
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: myapp-suffix
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: myapp
|
||||
namespace: test
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myapp
|
||||
namespace: test
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: myapp
|
||||
namespace: test
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: myapp
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: myapp
|
||||
namespace: test
|
||||
`)
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package resid
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
@@ -207,5 +208,6 @@ func (x Gvk) toKyamlTypeMeta() yaml.TypeMeta {
|
||||
// IsNamespaceableKind returns true if x is a namespaceable Gvk
|
||||
// Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace
|
||||
func (x Gvk) IsNamespaceableKind() bool {
|
||||
return x.toKyamlTypeMeta().IsNamespaceable()
|
||||
isNamespaceScoped, found := openapi.IsNamespaceScoped(x.toKyamlTypeMeta())
|
||||
return !found || isNamespaceScoped
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package resid
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var equalsTests = []struct {
|
||||
@@ -255,3 +257,40 @@ func TestSelectByGVK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNamespaceableKind(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
gvk Gvk
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
"namespaceable resource",
|
||||
Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"clusterscoped resource",
|
||||
Gvk{Group: "", Version: "v1", Kind: "Namespace"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"unknown resource (should default to namespaceable)",
|
||||
Gvk{Group: "example1.com", Version: "v1", Kind: "Bar"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"unknown resource (should default to namespaceable)",
|
||||
Gvk{Group: "apps", Version: "v1", Kind: "ClusterRoleBinding"},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
test := testCases[i]
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
isNamespaceable := test.gvk.IsNamespaceableKind()
|
||||
assert.Equal(t, test.expected, isNamespaceable)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ func TestResIdEquals(t *testing.T) {
|
||||
Name: "nm",
|
||||
},
|
||||
gVknResult: false,
|
||||
nsEquals: false,
|
||||
nsEquals: true,
|
||||
equals: false,
|
||||
},
|
||||
{
|
||||
@@ -376,7 +376,7 @@ func TestEffectiveNamespace(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
id: ResId{
|
||||
Gvk: Gvk{Group: "g", Version: "v", Kind: "Node"},
|
||||
Gvk: Gvk{Group: "", Version: "v1", Kind: "Node"},
|
||||
Name: "nm",
|
||||
},
|
||||
expected: TotallyNotANamespace,
|
||||
@@ -384,7 +384,7 @@ func TestEffectiveNamespace(t *testing.T) {
|
||||
{
|
||||
id: ResId{
|
||||
Namespace: "foo",
|
||||
Gvk: Gvk{Group: "g", Version: "v", Kind: "Node"},
|
||||
Gvk: Gvk{Group: "", Version: "v1", Kind: "Node"},
|
||||
Name: "nm",
|
||||
},
|
||||
expected: TotallyNotANamespace,
|
||||
|
||||
@@ -6,7 +6,6 @@ package resmap
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
@@ -510,51 +509,34 @@ func (m *resWrangler) appendReplaceOrMerge(
|
||||
return nil
|
||||
}
|
||||
|
||||
func anchorRegex(pattern string) string {
|
||||
if pattern == "" {
|
||||
return pattern
|
||||
}
|
||||
return "^" + pattern + "$"
|
||||
}
|
||||
|
||||
// Select returns a list of resources that
|
||||
// are selected by a Selector
|
||||
func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
|
||||
ns := regexp.MustCompile(anchorRegex(s.Namespace))
|
||||
nm := regexp.MustCompile(anchorRegex(s.Name))
|
||||
var result []*resource.Resource
|
||||
sr, err := types.NewSelectorRegex(&s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, r := range m.Resources() {
|
||||
curId := r.CurId()
|
||||
orgId := r.OrgId()
|
||||
|
||||
// matches the namespace when namespace is not empty in the selector
|
||||
// It first tries to match with the original namespace
|
||||
// then matches with the current namespace
|
||||
if s.Namespace != "" {
|
||||
matched := ns.MatchString(orgId.EffectiveNamespace())
|
||||
if !matched {
|
||||
matched = ns.MatchString(curId.EffectiveNamespace())
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !sr.MatchNamespace(orgId.EffectiveNamespace()) &&
|
||||
!sr.MatchNamespace(curId.EffectiveNamespace()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// matches the name when name is not empty in the selector
|
||||
// It first tries to match with the original name
|
||||
// then matches with the current name
|
||||
if s.Name != "" {
|
||||
matched := nm.MatchString(orgId.Name)
|
||||
if !matched {
|
||||
matched = nm.MatchString(curId.Name)
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !sr.MatchName(orgId.Name) &&
|
||||
!sr.MatchName(curId.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// matches the GVK
|
||||
if !r.GetGvk().IsSelected(&s.Gvk) {
|
||||
if !sr.MatchGvk(r.GetGvk()) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
||||
})
|
||||
r4 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
@@ -374,7 +374,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
||||
r5.AddNamePrefix("little-")
|
||||
r6 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "domino",
|
||||
@@ -384,7 +384,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
||||
r6.AddNamePrefix("little-")
|
||||
r7 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRoleBinding",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "meh",
|
||||
|
||||
19
api/types/helmchartargs.go
Normal file
19
api/types/helmchartargs.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// HelmChartArgs contains the metadata of how to generate a secret.
|
||||
type HelmChartArgs struct {
|
||||
ChartName string `json:"chartName,omitempty" yaml:"chartName,omitempty"`
|
||||
ChartVersion string `json:"chartVersion,omitempty" yaml:"chartVersion,omitempty"`
|
||||
ChartRepoURL string `json:"chartRepoUrl,omitempty" yaml:"chartRepoUrl,omitempty"`
|
||||
ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"`
|
||||
// Use chartRelease to keep compatible with old exec plugin
|
||||
ChartRepoName string `json:"chartRelease,omitempty" yaml:"chartRelease,omitempty"`
|
||||
HelmBin string `json:"helmBin,omitempty" yaml:"helmBin,omitempty"`
|
||||
HelmHome string `json:"helmHome,omitempty" yaml:"helmHome,omitempty"`
|
||||
Values string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
ReleaseName string `json:"releaseName,omitempty" yaml:"releaseName,omitempty"`
|
||||
ReleaseNamespace string `json:"releaseNamespace,omitempty" yaml:"releaseNamespace,omitempty"`
|
||||
}
|
||||
@@ -55,7 +55,7 @@ type Kustomization struct {
|
||||
// JSONPatches is a list of JSONPatch for applying JSON patch.
|
||||
// Format documented at https://tools.ietf.org/html/rfc6902
|
||||
// and http://jsonpatch.com
|
||||
PatchesJson6902 []PatchJson6902 `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"`
|
||||
PatchesJson6902 []Patch `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"`
|
||||
|
||||
// Patches is a list of patches, where each one can be either a
|
||||
// Strategic Merge Patch or a JSON patch.
|
||||
@@ -122,6 +122,11 @@ type Kustomization struct {
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"`
|
||||
|
||||
// HelmChartInflationGenerator is a list of helm chart configurations.
|
||||
// The resulting resource is a normal operand rendered from
|
||||
// a remote chart by `helm template`
|
||||
HelmChartInflationGenerator []HelmChartArgs `json:"helmChartInflationGenerator,omitempty" yaml:"helmChartInflationGenerator,omitempty"`
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"`
|
||||
|
||||
@@ -167,9 +172,7 @@ func (k *Kustomization) FixKustomizationPostUnmarshalling() {
|
||||
// has been processed.
|
||||
func (k *Kustomization) FixKustomizationPreMarshalling() {
|
||||
// PatchesJson6902 should be under the Patches field.
|
||||
for _, patch := range k.PatchesJson6902 {
|
||||
k.Patches = append(k.Patches, patch.ToPatch())
|
||||
}
|
||||
k.Patches = append(k.Patches, k.PatchesJson6902...)
|
||||
k.PatchesJson6902 = nil
|
||||
}
|
||||
|
||||
|
||||
@@ -17,3 +17,12 @@ type Patch struct {
|
||||
// Target points to the resources that the patch is applied to
|
||||
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
|
||||
// Equals return true if p equals o.
|
||||
func (p *Patch) Equals(o Patch) bool {
|
||||
targetEqual := (p.Target == o.Target) ||
|
||||
(p.Target != nil && o.Target != nil && *p.Target == *o.Target)
|
||||
return p.Path == o.Path &&
|
||||
p.Patch == o.Patch &&
|
||||
targetEqual
|
||||
}
|
||||
|
||||
125
api/types/patch_test.go
Normal file
125
api/types/patch_test.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
. "sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestPatchEquals(t *testing.T) {
|
||||
selector := Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
LabelSelector: "selector",
|
||||
AnnotationSelector: "selector",
|
||||
}
|
||||
type testcase struct {
|
||||
patch1 Patch
|
||||
patch2 Patch
|
||||
expect bool
|
||||
name string
|
||||
}
|
||||
testcases := []testcase{
|
||||
{
|
||||
name: "empty patches",
|
||||
patch1: Patch{},
|
||||
patch2: Patch{},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "full patches",
|
||||
patch1: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
Target: &Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
LabelSelector: "selector",
|
||||
AnnotationSelector: "selector",
|
||||
},
|
||||
},
|
||||
patch2: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
Target: &Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
LabelSelector: "selector",
|
||||
AnnotationSelector: "selector",
|
||||
},
|
||||
},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "same target",
|
||||
patch1: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
Target: &selector,
|
||||
},
|
||||
patch2: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
Target: &selector,
|
||||
},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "omit target",
|
||||
patch1: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
},
|
||||
patch2: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "one nil target",
|
||||
patch1: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
Target: &selector,
|
||||
},
|
||||
patch2: Patch{
|
||||
Path: "foo",
|
||||
Patch: "bar",
|
||||
},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
name: "different path",
|
||||
patch1: Patch{
|
||||
Path: "foo",
|
||||
},
|
||||
patch2: Patch{
|
||||
Path: "bar",
|
||||
},
|
||||
expect: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
if tc.expect != tc.patch1.Equals(tc.patch2) {
|
||||
t.Fatalf("%s: unexpected result %v", tc.name, !tc.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PatchJson6902 represents a json patch for an object
|
||||
// with format documented https://tools.ietf.org/html/rfc6902.
|
||||
type PatchJson6902 struct {
|
||||
// PatchTarget refers to a Kubernetes object that the json patch will be
|
||||
// applied to. It must refer to a Kubernetes resource under the
|
||||
// purview of this kustomization. PatchTarget should use the
|
||||
// raw name of the object (the name specified in its YAML,
|
||||
// before addition of a namePrefix and a nameSuffix).
|
||||
Target *PatchTarget `json:"target" yaml:"target"`
|
||||
|
||||
// relative file path for a json patch file inside a kustomization
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// inline patch string
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
}
|
||||
|
||||
// ToPatch converts a PatchJson6902 to its superset Patch.
|
||||
func (patch *PatchJson6902) ToPatch() Patch {
|
||||
selector := patch.Target.ToSelector()
|
||||
return Patch{Path: patch.Path, Patch: patch.Patch, Target: &selector}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// PatchTarget represents the kubernetes object that the patch is applied to
|
||||
type PatchTarget struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
}
|
||||
|
||||
// ToSelector converts a PatchTarget to a Selector.
|
||||
func (target *PatchTarget) ToSelector() Selector {
|
||||
return Selector{Name: target.Name, Namespace: target.Namespace, Gvk: target.Gvk}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
@@ -25,3 +27,89 @@ type Selector struct {
|
||||
// It matches with the resource labels.
|
||||
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
|
||||
}
|
||||
|
||||
// SelectorRegex is a Selector with regex in GVK
|
||||
// Any resource that matches intersection of all conditions
|
||||
// is included in this set.
|
||||
type SelectorRegex struct {
|
||||
selector *Selector
|
||||
groupRegex *regexp.Regexp
|
||||
versionRegex *regexp.Regexp
|
||||
kindRegex *regexp.Regexp
|
||||
nameRegex *regexp.Regexp
|
||||
namespaceRegex *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewSelectorRegex returns a pointer to a new SelectorRegex
|
||||
// which uses the same condition as s.
|
||||
func NewSelectorRegex(s *Selector) (*SelectorRegex, error) {
|
||||
sr := new(SelectorRegex)
|
||||
var err error
|
||||
sr.selector = s
|
||||
sr.groupRegex, err = regexp.Compile(anchorRegex(s.Gvk.Group))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.versionRegex, err = regexp.Compile(anchorRegex(s.Gvk.Version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.kindRegex, err = regexp.Compile(anchorRegex(s.Gvk.Kind))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.nameRegex, err = regexp.Compile(anchorRegex(s.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.namespaceRegex, err = regexp.Compile(anchorRegex(s.Namespace))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sr, nil
|
||||
}
|
||||
|
||||
func anchorRegex(pattern string) string {
|
||||
if pattern == "" {
|
||||
return pattern
|
||||
}
|
||||
return "^(?:" + pattern + ")$"
|
||||
}
|
||||
|
||||
// MatchGvk return true if gvk can be matched by s.
|
||||
func (s *SelectorRegex) MatchGvk(gvk resid.Gvk) bool {
|
||||
if len(s.selector.Gvk.Group) > 0 {
|
||||
if !s.groupRegex.MatchString(gvk.Group) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(s.selector.Gvk.Version) > 0 {
|
||||
if !s.versionRegex.MatchString(gvk.Version) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(s.selector.Gvk.Kind) > 0 {
|
||||
if !s.kindRegex.MatchString(gvk.Kind) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MatchName returns true if the name in selector is
|
||||
// empty or the n can be matches by the name in selector
|
||||
func (s *SelectorRegex) MatchName(n string) bool {
|
||||
if s.selector.Name == "" {
|
||||
return true
|
||||
}
|
||||
return s.nameRegex.MatchString(n)
|
||||
}
|
||||
|
||||
// MatchNamespace returns true if the namespace in selector is
|
||||
// empty or the ns can be matches by the namespace in selector
|
||||
func (s *SelectorRegex) MatchNamespace(ns string) bool {
|
||||
if s.selector.Namespace == "" {
|
||||
return true
|
||||
}
|
||||
return s.namespaceRegex.MatchString(ns)
|
||||
}
|
||||
|
||||
216
api/types/selector_test.go
Normal file
216
api/types/selector_test.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
. "sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestSelectorRegexMatchGvk(t *testing.T) {
|
||||
testcases := []struct {
|
||||
S Selector
|
||||
G resid.Gvk
|
||||
Expected bool
|
||||
}{
|
||||
{
|
||||
S: Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
},
|
||||
G: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "",
|
||||
Kind: "",
|
||||
},
|
||||
},
|
||||
G: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
},
|
||||
G: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "",
|
||||
},
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind",
|
||||
},
|
||||
},
|
||||
G: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "version",
|
||||
Kind: "kind2",
|
||||
},
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "g.*",
|
||||
Version: "\\d+",
|
||||
Kind: ".{4}",
|
||||
},
|
||||
},
|
||||
G: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "123",
|
||||
Kind: "abcd",
|
||||
},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Gvk: resid.Gvk{
|
||||
Group: "g.*",
|
||||
Version: "\\d+",
|
||||
Kind: ".{4}",
|
||||
},
|
||||
},
|
||||
G: resid.Gvk{
|
||||
Group: "group",
|
||||
Version: "123",
|
||||
Kind: "abc",
|
||||
},
|
||||
Expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
sr, err := NewSelectorRegex(&tc.S)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sr.MatchGvk(tc.G) != tc.Expected {
|
||||
t.Fatalf("unexpected result for selector gvk %s and gvk %s",
|
||||
tc.S.Gvk.String(), tc.G.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectorRegexMatchName(t *testing.T) {
|
||||
testcases := []struct {
|
||||
S Selector
|
||||
Name string
|
||||
Expected bool
|
||||
}{
|
||||
{
|
||||
S: Selector{
|
||||
Name: "foo",
|
||||
Namespace: "bar",
|
||||
},
|
||||
Name: "foo",
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Name: "foo",
|
||||
Namespace: "bar",
|
||||
},
|
||||
Name: "bar",
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Name: "f.*",
|
||||
},
|
||||
Name: "foo",
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Name: "b.*",
|
||||
},
|
||||
Name: "foo",
|
||||
Expected: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
sr, err := NewSelectorRegex(&tc.S)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sr.MatchName(tc.Name) != tc.Expected {
|
||||
t.Fatalf("unexpected result for selector name %s and name %s",
|
||||
tc.S.Name, tc.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectorRegexMatchNamespace(t *testing.T) {
|
||||
testcases := []struct {
|
||||
S Selector
|
||||
Namespace string
|
||||
Expected bool
|
||||
}{
|
||||
{
|
||||
S: Selector{
|
||||
Name: "bar",
|
||||
Namespace: "foo",
|
||||
},
|
||||
Namespace: "foo",
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Name: "foo",
|
||||
Namespace: "bar",
|
||||
},
|
||||
Namespace: "foo",
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Namespace: "f.*",
|
||||
},
|
||||
Namespace: "foo",
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
S: Selector{
|
||||
Namespace: "b.*",
|
||||
},
|
||||
Namespace: "foo",
|
||||
Expected: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
sr, err := NewSelectorRegex(&tc.S)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sr.MatchNamespace(tc.Namespace) != tc.Expected {
|
||||
t.Fatalf("unexpected result for selector namespace %s and namespace %s",
|
||||
tc.S.Namespace, tc.Namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package complete
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/posener/complete/v2"
|
||||
"github.com/posener/complete/v2/predict"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// NewCommand returns a new install-completion command
|
||||
func NewCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "install-completion",
|
||||
Short: commands.CompletionShort,
|
||||
Long: commands.CompletionLong,
|
||||
PreRunE: preRunE,
|
||||
Run: run,
|
||||
}
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
// install by default
|
||||
if os.Getenv("COMP_INSTALL") == "" {
|
||||
if err := errors.Wrap(os.Setenv("COMP_INSTALL", "1")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func run(cmd *cobra.Command, args []string) {
|
||||
// find the root command
|
||||
for cmd.Parent() != nil {
|
||||
cmd = cmd.Parent()
|
||||
}
|
||||
|
||||
// do completion
|
||||
Complete(cmd).Complete("kustomize")
|
||||
}
|
||||
|
||||
// Complete returns a completion command for a cobra command
|
||||
func Complete(cmd *cobra.Command) *complete.Command {
|
||||
cc := &complete.Command{
|
||||
Flags: map[string]complete.Predictor{},
|
||||
Sub: map[string]*complete.Command{},
|
||||
}
|
||||
if strings.Contains(cmd.Use, "DIR") {
|
||||
// if usage contains directory, then use a file predictor
|
||||
cc.Args = predict.Dirs("*")
|
||||
}
|
||||
|
||||
// add completion for each subcommand
|
||||
for i := range cmd.Commands() {
|
||||
c := cmd.Commands()[i]
|
||||
name := strings.Split(c.Use, " ")[0]
|
||||
cc.Sub[name] = Complete(c)
|
||||
}
|
||||
|
||||
// add completion for each flag
|
||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
||||
cc.Flags[flag.Name] = predict.Nothing
|
||||
})
|
||||
return cc
|
||||
}
|
||||
33
cmd/config/completion/completion.go
Normal file
33
cmd/config/completion/completion.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package completion
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "completion [bash|zsh|fish|powershell]",
|
||||
Short: "Generate shell completion script",
|
||||
Long: "Generate shell completion.",
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
||||
Args: cobra.ExactValidArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
switch args[0] {
|
||||
case "bash":
|
||||
cmd.Root().GenBashCompletion(os.Stdout)
|
||||
case "zsh":
|
||||
cmd.Root().GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
cmd.Root().GenPowerShellCompletion(os.Stdout)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/api"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/tutorials"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
)
|
||||
|
||||
// Export commands publicly for composition
|
||||
@@ -35,13 +36,13 @@ var (
|
||||
Wrap = commands.WrapCommand
|
||||
XArgs = commands.XArgsCommand
|
||||
|
||||
StackOnError = &commands.StackOnError
|
||||
ExitOnError = &commands.ExitOnError
|
||||
StackOnError = &runner.StackOnError
|
||||
ExitOnError = &runner.ExitOnError
|
||||
)
|
||||
|
||||
// AddCommands adds the cfg and fn commands to kustomize.
|
||||
func AddCommands(root *cobra.Command, name string) *cobra.Command {
|
||||
commands.ExitOnError = true
|
||||
runner.ExitOnError = true
|
||||
|
||||
root.PersistentFlags().BoolVar(StackOnError, "stack-trace", false,
|
||||
"print a stack-trace on error")
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
## install-completion
|
||||
## completion
|
||||
|
||||
Install shell completion.
|
||||
Generate shell completion.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Install shell completion for kustomize commands and flags -- supports bash, fish and zsh.
|
||||
Generate shell completion for `kustomize` -- supports bash, zsh, fish and powershell.
|
||||
|
||||
kustomize install-completion
|
||||
### Examples
|
||||
|
||||
Registers the completion command with known shells (e.g. .bashrc, .bash_profile, etc):
|
||||
# load completion for Bash
|
||||
source <(kustomize completion bash)
|
||||
|
||||
complete -C /Users/USER/go/bin/kustomize kustomize
|
||||
# install for Bash in Linux
|
||||
kustomize completion bash > /etc/bash_completion.d/kustomize
|
||||
|
||||
Because the completion command is embedded in kustomize directly, there is no need to update
|
||||
it separately from the kustomize binary.
|
||||
# install for Bash in MacOS
|
||||
kustomize completion bash > /usr/local/etc/bash_completion.d/kustomize
|
||||
|
||||
To uninstall shell completion run:
|
||||
# package for Bash
|
||||
kustomize completion bash > /usr/share/bash-completion/completions/kustomize
|
||||
|
||||
# package for zsh
|
||||
kustomize completion zsh > /usr/share/zsh/site-functions/_kustomize
|
||||
|
||||
COMP_UNINSTALL=1 kustomize install-completion
|
||||
|
||||
@@ -9,13 +9,11 @@ require (
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/posener/complete/v2 v2.0.1-alpha.12
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.6.1
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
k8s.io/apimachinery v0.17.3
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1
|
||||
k8s.io/apimachinery v0.18.10
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4
|
||||
)
|
||||
|
||||
@@ -34,7 +34,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -45,10 +44,9 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -122,8 +120,8 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
|
||||
@@ -141,21 +139,19 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
@@ -165,7 +161,7 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
@@ -200,7 +196,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
@@ -217,8 +212,7 @@ github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
@@ -227,13 +221,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete/v2 v2.0.1-alpha.12 h1:0wvkuDfHb5vSZlNBYgpEH4XQHpF46MjLPHav8XC77Nc=
|
||||
github.com/posener/complete/v2 v2.0.1-alpha.12/go.mod h1://JlL91cS2JV7rOl6LVHrRqBXoBUecJu3ILQPgbJiMQ=
|
||||
github.com/posener/script v1.0.4 h1:nSuXW5ZdmFnQIueLB2s0qvs4oNsUloM1Zydzh75v42w=
|
||||
github.com/posener/script v1.0.4/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
@@ -268,7 +257,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@@ -339,9 +327,9 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c h1:Vco5b+cuG5NNfORVxZy6bYZQ7rsigisU1WQFkvQ0L5E=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -392,16 +380,17 @@ gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/apimachinery v0.17.3 h1:f+uZV6rm4/tHE7xXgLyToprg6xWairaClGVkm2t8omg=
|
||||
k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
||||
k8s.io/apimachinery v0.18.10 h1:Zupk3lPrUfhCF9puTpA8EvEfPsrhNZtrpOqdp66mKVs=
|
||||
k8s.io/apimachinery v0.18.10/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEXk=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1 h1:T7aNUraSioQp0NHJZtYjIhL/q8mqRzCiHcAKdvo09go=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.1/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4 h1:DDuzZtjIzFqp2IPy4DTyCI69Cl3bDgcJODjI6sjF9NY=
|
||||
sigs.k8s.io/kustomize/kyaml v0.9.4/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
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.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
@@ -27,7 +28,7 @@ func NewAnnotateRunner(parent string) *AnnotateRunner {
|
||||
Example: commands.AnnotateExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(parent, c)
|
||||
runner.FixDocs(parent, c)
|
||||
r.Command = c
|
||||
c.Flags().StringVar(&r.Kind, "kind", "", "Resource kind to annotate")
|
||||
c.Flags().StringVar(&r.ApiVersion, "apiVersion", "", "Resource apiVersion to annotate")
|
||||
@@ -62,29 +63,29 @@ func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
|
||||
input = []kio.Reader{rw}
|
||||
output = []kio.Writer{rw}
|
||||
|
||||
return handleError(c, kio.Pipeline{
|
||||
return runner.HandleError(c, kio.Pipeline{
|
||||
Inputs: input,
|
||||
Filters: []kio.Filter{r},
|
||||
Outputs: output,
|
||||
}.Execute())
|
||||
}
|
||||
|
||||
e := executeCmdOnPkgs{
|
||||
writer: c.OutOrStdout(),
|
||||
needOpenAPI: false,
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
rootPkgPath: args[0],
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
Writer: c.OutOrStdout(),
|
||||
NeedOpenAPI: false,
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
RootPkgPath: args[0],
|
||||
}
|
||||
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *AnnotateRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *AnnotateRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
rw := &kio.LocalPackageReadWriter{
|
||||
PackagePath: pkgPath,
|
||||
NoDeleteFiles: true,
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
@@ -30,7 +31,7 @@ func GetCatRunner(name string) *CatRunner {
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.Format, "format", true,
|
||||
"format resource config yaml before printing.")
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
|
||||
@@ -95,21 +96,21 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return handleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute())
|
||||
return runner.HandleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute())
|
||||
}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
e := executeCmdOnPkgs{
|
||||
writer: out,
|
||||
needOpenAPI: false,
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
rootPkgPath: args[0],
|
||||
skipPkgPathPrint: true,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
Writer: out,
|
||||
NeedOpenAPI: false,
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
RootPkgPath: args[0],
|
||||
SkipPkgPathPrint: true,
|
||||
}
|
||||
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -120,7 +121,7 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CatRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *CatRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()}
|
||||
out := &bytes.Buffer{}
|
||||
outputs, err := r.out(out)
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||
@@ -63,7 +64,7 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
|
||||
set.Flags().BoolVarP(&r.CreateSetter.RecurseSubPackages, "recurse-subpackages", "R", false,
|
||||
"creates setter recursively in all the nested subpackages")
|
||||
set.Flags().MarkHidden("version")
|
||||
fixDocs(parent, set)
|
||||
runner.FixDocs(parent, set)
|
||||
r.Command = set
|
||||
return r
|
||||
}
|
||||
@@ -81,7 +82,7 @@ type CreateSetterRunner struct {
|
||||
}
|
||||
|
||||
func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error {
|
||||
return handleError(c, r.createSetter(c, args))
|
||||
return runner.HandleError(c, r.createSetter(c, args))
|
||||
}
|
||||
|
||||
func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
@@ -179,16 +180,16 @@ func (r *CreateSetterRunner) processSchema() error {
|
||||
|
||||
func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error {
|
||||
if setterVersion == "v2" {
|
||||
e := executeCmdOnPkgs{
|
||||
needOpenAPI: true,
|
||||
writer: c.OutOrStdout(),
|
||||
rootPkgPath: args[0],
|
||||
recurseSubPackages: r.CreateSetter.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: true,
|
||||
Writer: c.OutOrStdout(),
|
||||
RootPkgPath: args[0],
|
||||
RecurseSubPackages: r.CreateSetter.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
}
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -204,7 +205,7 @@ func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CreateSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *CreateSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
r.CreateSetter = settersutil.SetterCreator{
|
||||
Name: r.CreateSetter.Name,
|
||||
SetBy: r.CreateSetter.SetBy,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||
)
|
||||
|
||||
@@ -32,7 +33,7 @@ func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
|
||||
"creates substitution recursively in all the nested subpackages")
|
||||
_ = cs.MarkFlagRequired("pattern")
|
||||
_ = cs.MarkFlagRequired("field-value")
|
||||
fixDocs(parent, cs)
|
||||
runner.FixDocs(parent, cs)
|
||||
r.Command = cs
|
||||
return r
|
||||
}
|
||||
@@ -49,22 +50,22 @@ type CreateSubstitutionRunner struct {
|
||||
}
|
||||
|
||||
func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error {
|
||||
e := executeCmdOnPkgs{
|
||||
needOpenAPI: true,
|
||||
writer: c.OutOrStdout(),
|
||||
rootPkgPath: args[0],
|
||||
recurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: true,
|
||||
Writer: c.OutOrStdout(),
|
||||
RootPkgPath: args[0],
|
||||
RecurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
}
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CreateSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *CreateSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
r.CreateSubstitution = settersutil.SubstitutionCreator{
|
||||
Name: r.CreateSubstitution.Name,
|
||||
FieldName: r.CreateSubstitution.FieldName,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||
)
|
||||
@@ -29,7 +30,7 @@ func NewDeleteSetterRunner(parent string) *DeleteSetterRunner {
|
||||
}
|
||||
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
|
||||
"deletes setter recursively in all the nested subpackages")
|
||||
fixDocs(parent, c)
|
||||
runner.FixDocs(parent, c)
|
||||
r.Command = c
|
||||
|
||||
return r
|
||||
@@ -56,22 +57,21 @@ func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error {
|
||||
e := executeCmdOnPkgs{
|
||||
needOpenAPI: true,
|
||||
writer: c.OutOrStdout(),
|
||||
rootPkgPath: args[0],
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: true,
|
||||
Writer: c.OutOrStdout(),
|
||||
RootPkgPath: args[0],
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
}
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DeleteSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
|
||||
func (r *DeleteSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
r.DeleteSetter = settersutil.DeleterCreator{
|
||||
Name: r.DeleteSetter.Name,
|
||||
DefinitionPrefix: fieldmeta.SetterDefinitionPrefix,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
||||
)
|
||||
@@ -25,7 +26,7 @@ func NewDeleteSubstitutionRunner(parent string) *DeleteSubstitutionRunner {
|
||||
}
|
||||
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
|
||||
"deletes substitution recursively in all the nested subpackages")
|
||||
fixDocs(parent, c)
|
||||
runner.FixDocs(parent, c)
|
||||
r.Command = c
|
||||
|
||||
return r
|
||||
@@ -52,21 +53,21 @@ func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) erro
|
||||
}
|
||||
|
||||
func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error {
|
||||
e := executeCmdOnPkgs{
|
||||
needOpenAPI: true,
|
||||
writer: c.OutOrStdout(),
|
||||
rootPkgPath: args[0],
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: true,
|
||||
Writer: c.OutOrStdout(),
|
||||
RootPkgPath: args[0],
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
}
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DeleteSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *DeleteSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
r.DeleteSubstitution = settersutil.DeleterCreator{
|
||||
Name: r.DeleteSubstitution.Name,
|
||||
DefinitionPrefix: fieldmeta.SubstitutionDefinitionPrefix,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/krmfile"
|
||||
)
|
||||
@@ -26,7 +27,7 @@ func GetInitRunner(name string) *InitRunner {
|
||||
Example: commands.InitExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters2"
|
||||
@@ -37,7 +38,7 @@ func NewListSettersRunner(parent string) *ListSettersRunner {
|
||||
"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)
|
||||
runner.FixDocs(parent, c)
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
@@ -67,24 +68,24 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
|
||||
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
|
||||
if setterVersion == "v2" {
|
||||
e := executeCmdOnPkgs{
|
||||
needOpenAPI: true,
|
||||
writer: c.OutOrStdout(),
|
||||
rootPkgPath: args[0],
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: true,
|
||||
Writer: c.OutOrStdout(),
|
||||
RootPkgPath: args[0],
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
}
|
||||
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return handleError(c, lookup(r.Lookup, c, args))
|
||||
return runner.HandleError(c, lookup(r.Lookup, c, args))
|
||||
}
|
||||
|
||||
func (r *ListSettersRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *ListSettersRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
r.List = setters2.List{
|
||||
Name: r.List.Name,
|
||||
OpenAPIFileName: ext.KRMFileName(),
|
||||
@@ -107,7 +108,7 @@ func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath s
|
||||
return err
|
||||
}
|
||||
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", "IS SET"})
|
||||
for i := range r.List.Setters {
|
||||
s := r.List.Setters[i]
|
||||
v := s.Value
|
||||
@@ -117,20 +118,23 @@ func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath s
|
||||
v = strings.Join(s.ListValues, ",")
|
||||
v = fmt.Sprintf("[%s]", v)
|
||||
}
|
||||
var required string
|
||||
required := "No"
|
||||
if s.Required {
|
||||
required = "Yes"
|
||||
} else {
|
||||
required = "No"
|
||||
}
|
||||
isSet := "No"
|
||||
if s.IsSet {
|
||||
isSet = "Yes"
|
||||
}
|
||||
|
||||
table.Append([]string{
|
||||
s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count), required})
|
||||
s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count), required, isSet})
|
||||
}
|
||||
table.Render()
|
||||
|
||||
if len(r.List.Setters) == 0 {
|
||||
// exit non-0 if no matching setters are found
|
||||
if ExitOnError {
|
||||
if runner.ExitOnError {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ metadata:
|
||||
spec:
|
||||
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
replicas 3 me hello world 1 Yes
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
replicas 3 me hello world 1 Yes No
|
||||
`,
|
||||
},
|
||||
|
||||
@@ -72,8 +72,8 @@ metadata:
|
||||
spec:
|
||||
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
replicas 4 me hello world 1 No
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
replicas 4 me hello world 1 No No
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -131,10 +131,10 @@ spec:
|
||||
- name: nginx2
|
||||
image: nginx # {"$ref": "#/definitions/io.k8s.cli.setters.image"}
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
image nginx me2 hello world 2 2 No
|
||||
replicas 3 me1 hello world 1 1 No
|
||||
tag 1.7.9 me3 hello world 3 1 Yes
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
image nginx me2 hello world 2 2 No No
|
||||
replicas 3 me1 hello world 1 1 No No
|
||||
tag 1.7.9 me3 hello world 3 1 Yes No
|
||||
--------------- ----------- --------------
|
||||
SUBSTITUTION PATTERN REFERENCES
|
||||
image IMAGE:TAG [image,tag]
|
||||
@@ -207,10 +207,10 @@ spec:
|
||||
- name: nginx2
|
||||
image: nginx
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
image nginx me2 hello world 2 3 No
|
||||
replicas 3 me1 hello world 1 2 No
|
||||
tag 1.7.9 me3 hello world 3 2 No
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
image nginx me2 hello world 2 3 No No
|
||||
replicas 3 me1 hello world 1 2 No No
|
||||
tag 1.7.9 me3 hello world 3 2 No No
|
||||
--------------- ----------- --------------
|
||||
SUBSTITUTION PATTERN REFERENCES
|
||||
image IMAGE:TAG [image,tag]
|
||||
@@ -284,8 +284,8 @@ spec:
|
||||
- name: nginx2
|
||||
image: nginx
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
image nginx me2 hello world 2 3 Yes
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
image nginx me2 hello world 2 3 Yes No
|
||||
`,
|
||||
},
|
||||
|
||||
@@ -324,8 +324,8 @@ spec:
|
||||
- "b"
|
||||
- "c"
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
list [a,b,c] me hello world 1 Yes
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
list [a,b,c] me hello world 1 Yes No
|
||||
`,
|
||||
},
|
||||
|
||||
@@ -390,10 +390,10 @@ openAPI:
|
||||
name: my-other-setter
|
||||
value: nginxotherthing
|
||||
`,
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
my-image-setter nginx 2 No
|
||||
my-other-setter nginxotherthing 1 No
|
||||
my-tag-setter 1.7.9 2 Yes
|
||||
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
my-image-setter nginx 2 No No
|
||||
my-other-setter nginxotherthing 1 No No
|
||||
my-tag-setter 1.7.9 2 Yes Yes
|
||||
------------------ ------------------------------------------------ -----------------------------------
|
||||
SUBSTITUTION PATTERN REFERENCES
|
||||
my-image-subst ${my-image-setter}::${my-tag-setter} [my-image-setter,my-tag-setter]
|
||||
@@ -476,20 +476,20 @@ func TestListSettersSubPackages(t *testing.T) {
|
||||
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
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
image mysql 1 No No
|
||||
namespace myspace 1 No No
|
||||
tag 1.7.9 1 No No
|
||||
--------------- ----------------- --------------
|
||||
SUBSTITUTION PATTERN REFERENCES
|
||||
image-tag ${image}:${tag} [image,tag]
|
||||
|
||||
test/testdata/dataset-with-setters/mysql/nosetters/
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
|
||||
test/testdata/dataset-with-setters/mysql/storage/
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
namespace myspace 1 No
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
namespace myspace 1 No No
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -499,10 +499,10 @@ test/testdata/dataset-with-setters/mysql/storage/
|
||||
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
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
image mysql 1 No No
|
||||
namespace myspace 1 No No
|
||||
tag 1.7.9 1 No No
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||
@@ -31,7 +32,7 @@ func NewSetRunner(parent string) *SetRunner {
|
||||
PreRunE: r.preRunE,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(parent, c)
|
||||
runner.FixDocs(parent, c)
|
||||
r.Command = c
|
||||
c.Flags().StringArrayVar(&r.Values, "values", []string{},
|
||||
"optional flag, the values of the setter to be set to")
|
||||
@@ -131,26 +132,26 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
|
||||
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
|
||||
if setterVersion == "v2" {
|
||||
e := executeCmdOnPkgs{
|
||||
needOpenAPI: true,
|
||||
writer: c.OutOrStdout(),
|
||||
rootPkgPath: args[0],
|
||||
recurseSubPackages: r.Set.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: true,
|
||||
Writer: c.OutOrStdout(),
|
||||
RootPkgPath: args[0],
|
||||
RecurseSubPackages: r.Set.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
}
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if len(args) > 2 || c.Flag("values").Changed {
|
||||
return handleError(c, r.perform(c, args))
|
||||
return runner.HandleError(c, r.perform(c, args))
|
||||
}
|
||||
return handleError(c, lookup(r.Lookup, c, args))
|
||||
return runner.HandleError(c, lookup(r.Lookup, c, args))
|
||||
}
|
||||
|
||||
func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *SetRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
r.Set = settersutil.FieldSetter{
|
||||
Name: r.Set.Name,
|
||||
Value: r.Set.Value,
|
||||
@@ -162,6 +163,7 @@ func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
OpenAPIFileName: ext.KRMFileName(),
|
||||
ResourcesPath: pkgPath,
|
||||
RecurseSubPackages: r.Set.RecurseSubPackages,
|
||||
IsSet: true,
|
||||
}
|
||||
count, err := r.Set.Set()
|
||||
if err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
@@ -135,5 +136,5 @@ func (r *WrapRunner) runE(c *cobra.Command, args []string) error {
|
||||
Writer: c.OutOrStdout(),
|
||||
WrappingKind: kio.ResourceListKind,
|
||||
WrappingAPIVersion: kio.ResourceListAPIVersion}}}.Execute()
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -211,7 +212,7 @@ func (r *XArgsRunner) runE(c *cobra.Command, _ []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return handleError(c, run.Run())
|
||||
return runner.HandleError(c, run.Run())
|
||||
}
|
||||
|
||||
func parseYNode(node *yaml.Node) string {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/sets"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
@@ -26,7 +27,7 @@ func GetCountRunner(name string) *CountRunner {
|
||||
Example: commands.CountExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.Kind, "kind", true,
|
||||
"count resources by kind.")
|
||||
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
|
||||
@@ -51,24 +52,24 @@ func (r *CountRunner) runE(c *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
input := &kio.ByteReader{Reader: c.InOrStdin()}
|
||||
|
||||
return handleError(c, kio.Pipeline{
|
||||
return runner.HandleError(c, kio.Pipeline{
|
||||
Inputs: []kio.Reader{input},
|
||||
Outputs: r.out(c.OutOrStdout()),
|
||||
}.Execute())
|
||||
}
|
||||
|
||||
e := executeCmdOnPkgs{
|
||||
writer: c.OutOrStdout(),
|
||||
needOpenAPI: false,
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
rootPkgPath: args[0],
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
Writer: c.OutOrStdout(),
|
||||
NeedOpenAPI: false,
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
RootPkgPath: args[0],
|
||||
}
|
||||
|
||||
return e.execute()
|
||||
return e.Execute()
|
||||
}
|
||||
|
||||
func (r *CountRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *CountRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()}
|
||||
|
||||
err := kio.Pipeline{
|
||||
|
||||
@@ -35,8 +35,8 @@ openAPI:
|
||||
},
|
||||
expectedStdOut: `
|
||||
./
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
replicas 3 1 No
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
|
||||
replicas 3 1 No No
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
@@ -25,7 +26,7 @@ func GetFmtRunner(name string) *FmtRunner {
|
||||
RunE: r.runE,
|
||||
PreRunE: r.preRunE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().StringVar(&r.FilenamePattern, "pattern", filters.DefaultFilenamePattern,
|
||||
`pattern to use for generating filenames for resources -- may contain the following
|
||||
formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace', '%k': 'kind'}`)
|
||||
@@ -74,20 +75,20 @@ func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
|
||||
Writer: c.OutOrStdout(),
|
||||
KeepReaderAnnotations: r.KeepAnnotations,
|
||||
}
|
||||
return handleError(c, kio.Pipeline{
|
||||
return runner.HandleError(c, kio.Pipeline{
|
||||
Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute())
|
||||
}
|
||||
|
||||
for _, rootPkgPath := range args {
|
||||
e := executeCmdOnPkgs{
|
||||
writer: c.OutOrStdout(),
|
||||
needOpenAPI: false,
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
rootPkgPath: rootPkgPath,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
Writer: c.OutOrStdout(),
|
||||
NeedOpenAPI: false,
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
RootPkgPath: rootPkgPath,
|
||||
}
|
||||
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -95,7 +96,7 @@ func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FmtRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *FmtRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
rw := &kio.LocalPackageReadWriter{
|
||||
NoDeleteFiles: true,
|
||||
PackagePath: pkgPath,
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"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/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
@@ -29,7 +30,7 @@ func GetGrepRunner(name string) *GrepRunner {
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(2),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true,
|
||||
"annotate resources with their file origins.")
|
||||
c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "", false,
|
||||
@@ -66,7 +67,7 @@ func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
|
||||
return qa.Cmp(qb), err
|
||||
}
|
||||
parts, err := parseFieldPath(args[0])
|
||||
parts, err := runner.ParseFieldPath(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -105,7 +106,7 @@ func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
|
||||
if len(args) == 1 {
|
||||
input := &kio.ByteReader{Reader: c.InOrStdin()}
|
||||
return handleError(c, kio.Pipeline{
|
||||
return runner.HandleError(c, kio.Pipeline{
|
||||
Inputs: []kio.Reader{input},
|
||||
Filters: []kio.Filter{r.GrepFilter},
|
||||
Outputs: []kio.Writer{kio.ByteWriter{
|
||||
@@ -117,16 +118,16 @@ func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
|
||||
|
||||
out := bytes.Buffer{}
|
||||
|
||||
e := executeCmdOnPkgs{
|
||||
writer: &out,
|
||||
needOpenAPI: false,
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
rootPkgPath: args[1],
|
||||
skipPkgPathPrint: true,
|
||||
e := runner.ExecuteCmdOnPkgs{
|
||||
Writer: &out,
|
||||
NeedOpenAPI: false,
|
||||
RecurseSubPackages: r.RecurseSubPackages,
|
||||
CmdRunner: r,
|
||||
RootPkgPath: args[1],
|
||||
SkipPkgPathPrint: true,
|
||||
}
|
||||
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -138,7 +139,7 @@ func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
|
||||
|
||||
}
|
||||
|
||||
func (r *GrepRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *GrepRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()}
|
||||
out := &bytes.Buffer{}
|
||||
err := kio.Pipeline{
|
||||
|
||||
@@ -6,6 +6,7 @@ package commands
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
@@ -19,7 +20,7 @@ func GetMergeRunner(name string) *MergeRunner {
|
||||
Example: commands.MergeExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
r.Command = c
|
||||
r.Command.Flags().BoolVar(&r.InvertOrder, "invert-order", false,
|
||||
"if true, merge Resources in the reverse order")
|
||||
@@ -64,5 +65,5 @@ func (r *MergeRunner) runE(c *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
filters := []kio.Filter{filters.MergeFilter{}, filters.FormatFilter{}}
|
||||
return handleError(c, kio.Pipeline{Inputs: inputs, Filters: filters, Outputs: outputs}.Execute())
|
||||
return runner.HandleError(c, kio.Pipeline{Inputs: inputs, Filters: filters, Outputs: outputs}.Execute())
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package commands
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
|
||||
@@ -18,7 +19,7 @@ func GetMerge3Runner(name string) *Merge3Runner {
|
||||
Example: commands.Merge3Examples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().StringVar(&r.ancestor, "ancestor", "",
|
||||
"Path to original package")
|
||||
c.Flags().StringVar(&r.fromDir, "from", "",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
@@ -29,7 +30,7 @@ func GetRunFnRunner(name string) *RunFnRunner {
|
||||
RunE: r.runE,
|
||||
PreRunE: r.preRunE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
r.Command = c
|
||||
@@ -70,6 +71,8 @@ func GetRunFnRunner(name string) *RunFnRunner {
|
||||
r.Command.Flags().StringArrayVarP(
|
||||
&r.Env, "env", "e", []string{},
|
||||
"a list of environment variables to be used by functions")
|
||||
r.Command.Flags().BoolVar(
|
||||
&r.AsCurrentUser, "as-current-user", false, "use the uid and gid that kpt is running with to run the function in the container")
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -97,10 +100,11 @@ type RunFnRunner struct {
|
||||
Mounts []string
|
||||
LogSteps bool
|
||||
Env []string
|
||||
AsCurrentUser bool
|
||||
}
|
||||
|
||||
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
|
||||
return handleError(c, r.RunFns.Execute())
|
||||
return runner.HandleError(c, r.RunFns.Execute())
|
||||
}
|
||||
|
||||
// getContainerFunctions parses the commandline flags and arguments into explicit
|
||||
@@ -312,6 +316,7 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
ResultsDir: r.ResultsDir,
|
||||
LogSteps: r.LogSteps,
|
||||
Env: r.Env,
|
||||
AsCurrentUser: r.AsCurrentUser,
|
||||
}
|
||||
|
||||
// don't consider args for the function
|
||||
|
||||
@@ -300,6 +300,16 @@ apiVersion: v1
|
||||
Env: []string{"FOO=BAR", "BAR"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "as current user",
|
||||
args: []string{"run", "dir", "--as-current-user"},
|
||||
path: "dir",
|
||||
expectedStruct: &runfn.RunFns{
|
||||
Path: "dir",
|
||||
AsCurrentUser: true,
|
||||
Env: []string{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
|
||||
@@ -6,6 +6,7 @@ package commands
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
)
|
||||
@@ -21,7 +22,7 @@ func GetSinkRunner(name string) *SinkRunner {
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
@@ -49,5 +50,5 @@ func (r *SinkRunner) runE(c *cobra.Command, args []string) error {
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: c.InOrStdin()}},
|
||||
Outputs: outputs}.Execute()
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -22,7 +23,7 @@ func GetSourceRunner(name string) *SourceRunner {
|
||||
Example: commands.SourceExamples,
|
||||
RunE: r.runE,
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind,
|
||||
"output using this format.")
|
||||
c.Flags().StringVar(&r.WrapApiVersion, "wrap-version", kio.ResourceListAPIVersion,
|
||||
@@ -78,5 +79,5 @@ func (r *SourceRunner) runE(c *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
err := kio.Pipeline{Inputs: inputs, Outputs: outputs}.Execute()
|
||||
return handleError(c, err)
|
||||
return runner.HandleError(c, err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/cmd/config/runner"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -26,7 +27,7 @@ func GetTreeRunner(name string) *TreeRunner {
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
runner.FixDocs(name, c)
|
||||
|
||||
// TODO(pwittrock): Figure out if these are the right things to expose, and consider making it
|
||||
// a list of options instead of individual flags
|
||||
@@ -91,7 +92,7 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
|
||||
|
||||
var fields []kio.TreeWriterField
|
||||
for _, field := range r.fields {
|
||||
path, err := parseFieldPath(field)
|
||||
path, err := runner.ParseFieldPath(field)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -155,7 +156,7 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
|
||||
ExcludeNonLocalConfig: r.excludeNonLocal,
|
||||
}}
|
||||
|
||||
return handleError(c, kio.Pipeline{
|
||||
return runner.HandleError(c, kio.Pipeline{
|
||||
Inputs: []kio.Reader{input},
|
||||
Filters: fltrs,
|
||||
Outputs: []kio.Writer{kio.TreeWriter{
|
||||
|
||||
@@ -35,22 +35,26 @@ var CatExamples = `
|
||||
# unwrap Resource config from a directory in an ResourceList
|
||||
... | kustomize cfg cat`
|
||||
|
||||
var CompletionShort = `Install shell completion.`
|
||||
var CompletionShort = `Generate shell completion.`
|
||||
var CompletionLong = `
|
||||
Install shell completion for kustomize commands and flags -- supports bash, fish and zsh.
|
||||
Generate shell completion for ` + "`" + `kustomize` + "`" + ` -- supports bash, zsh, fish and powershell.
|
||||
`
|
||||
var CompletionExamples = `
|
||||
# load completion for Bash
|
||||
source <(kustomize completion bash)
|
||||
|
||||
kustomize install-completion
|
||||
# install for Bash in Linux
|
||||
kustomize completion bash > /etc/bash_completion.d/kustomize
|
||||
|
||||
Registers the completion command with known shells (e.g. .bashrc, .bash_profile, etc):
|
||||
# install for Bash in MacOS
|
||||
kustomize completion bash > /usr/local/etc/bash_completion.d/kustomize
|
||||
|
||||
complete -C /Users/USER/go/bin/kustomize kustomize
|
||||
# package for Bash
|
||||
kustomize completion bash > /usr/share/bash-completion/completions/kustomize
|
||||
|
||||
Because the completion command is embedded in kustomize directly, there is no need to update
|
||||
it separately from the kustomize binary.
|
||||
|
||||
To uninstall shell completion run:
|
||||
|
||||
COMP_UNINSTALL=1 kustomize install-completion`
|
||||
# package for zsh
|
||||
kustomize completion zsh > /usr/share/zsh/site-functions/_kustomize
|
||||
`
|
||||
|
||||
var CountShort = `[Alpha] Count Resources Config from a local directory.`
|
||||
var CountLong = `
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
package commands
|
||||
package runner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -17,82 +17,79 @@ import (
|
||||
"sigs.k8s.io/kustomize/kyaml/pathutil"
|
||||
)
|
||||
|
||||
// cmdRunner interface holds executeCmd definition which executes respective command's
|
||||
// CmdRunner interface holds ExecuteCmd definition which executes respective command's
|
||||
// implementation on single package
|
||||
type cmdRunner interface {
|
||||
executeCmd(w io.Writer, pkgPath string) error
|
||||
type CmdRunner interface {
|
||||
ExecuteCmd(w io.Writer, pkgPath string) error
|
||||
}
|
||||
|
||||
// executeCmdOnPkgs struct holds the parameters necessary to
|
||||
// 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
|
||||
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
|
||||
// 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 {
|
||||
pkgsPaths, err := pathutil.DirsWithFile(e.rootPkgPath, ext.KRMFileName(), e.recurseSubPackages)
|
||||
func (e ExecuteCmdOnPkgs) Execute() error {
|
||||
pkgsPaths, err := pathutil.DirsWithFile(e.RootPkgPath, ext.KRMFileName(), 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 {
|
||||
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", ext.KRMFileName(), e.rootPkgPath)
|
||||
return errors.Errorf("unable to find %q in package %q", ext.KRMFileName(), e.RootPkgPath)
|
||||
}
|
||||
|
||||
// add root path for commands which doesn't need openAPI(ex: annotate, fmt)
|
||||
pkgsPaths = []string{e.rootPkgPath}
|
||||
pkgsPaths = []string{e.RootPkgPath}
|
||||
}
|
||||
|
||||
// for commands which doesn't need openAPI file, make sure that the root package is
|
||||
// included all the times
|
||||
if !e.needOpenAPI && !containsString(pkgsPaths, e.rootPkgPath) {
|
||||
pkgsPaths = append([]string{e.rootPkgPath}, pkgsPaths...)
|
||||
if !e.NeedOpenAPI && !containsString(pkgsPaths, e.RootPkgPath) {
|
||||
pkgsPaths = append([]string{e.RootPkgPath}, pkgsPaths...)
|
||||
}
|
||||
|
||||
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, ext.KRMFileName())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !e.skipPkgPathPrint {
|
||||
fmt.Fprintf(e.writer, "%s/\n", pkgPath)
|
||||
}
|
||||
|
||||
err := e.cmdRunner.executeCmd(e.writer, pkgPath)
|
||||
err := e.processPkg(pkgsPaths[i])
|
||||
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, ext.KRMFileName())); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(e.Writer, "\n")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseFieldPath parse a flag value into a field path
|
||||
func parseFieldPath(path string) ([]string, error) {
|
||||
func (e ExecuteCmdOnPkgs) processPkg(pkgPath string) error {
|
||||
// Add schema present in openAPI file for current package
|
||||
if e.NeedOpenAPI {
|
||||
clean, err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clean()
|
||||
}
|
||||
|
||||
if !e.SkipPkgPathPrint {
|
||||
fmt.Fprintf(e.Writer, "%s/\n", pkgPath)
|
||||
}
|
||||
|
||||
return e.CmdRunner.ExecuteCmd(e.Writer, pkgPath)
|
||||
}
|
||||
|
||||
// ParseFieldPath parse a flag value into a field path
|
||||
func ParseFieldPath(path string) ([]string, error) {
|
||||
// fixup '\.' so we don't split on it
|
||||
match := strings.ReplaceAll(path, "\\.", "$$$$")
|
||||
parts := strings.Split(match, ".")
|
||||
@@ -118,7 +115,7 @@ func parseFieldPath(path string) ([]string, error) {
|
||||
return newParts, nil
|
||||
}
|
||||
|
||||
func handleError(c *cobra.Command, err error) error {
|
||||
func HandleError(c *cobra.Command, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -145,7 +142,7 @@ var StackOnError bool
|
||||
const cmdName = "kustomize config"
|
||||
|
||||
// FixDocs replaces instances of old with new in the docs for c
|
||||
func fixDocs(new string, c *cobra.Command) {
|
||||
func FixDocs(new string, c *cobra.Command) {
|
||||
c.Use = strings.ReplaceAll(c.Use, cmdName, new)
|
||||
c.Short = strings.ReplaceAll(c.Short, cmdName, new)
|
||||
c.Long = strings.ReplaceAll(c.Long, cmdName, new)
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package commands
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -76,14 +76,14 @@ ${baseDir}/subpkg2/subpkg3/
|
||||
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,
|
||||
e := ExecuteCmdOnPkgs{
|
||||
NeedOpenAPI: test.needOpenAPI,
|
||||
Writer: actual,
|
||||
RootPkgPath: filepath.Join(dir, test.pkgPath),
|
||||
RecurseSubPackages: test.recurse,
|
||||
CmdRunner: r,
|
||||
}
|
||||
err := e.execute()
|
||||
err := e.Execute()
|
||||
if test.errMsg == "" {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -170,7 +170,7 @@ func createTestDirStructure(dir string) error {
|
||||
|
||||
type TestRunner struct{}
|
||||
|
||||
func (r *TestRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
func (r *TestRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
|
||||
children, err := ioutil.ReadDir(pkgPath)
|
||||
if err != nil {
|
||||
return err
|
||||
15
cmd/gorepomod/Makefile
Normal file
15
cmd/gorepomod/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
MYGOBIN := $(shell go env GOPATH)/bin
|
||||
|
||||
$(MYGOBIN)/gorepomod: usage.go
|
||||
go install .
|
||||
|
||||
.PHONY: test
|
||||
test: $(MYGOBIN)/gorepomod
|
||||
go test ./...
|
||||
|
||||
usage.go: README.md $(MYGOBIN)/goimports
|
||||
go generate . \
|
||||
$(MYGOBIN)/goimports -w usage.go
|
||||
|
||||
$(MYGOBIN)/goimports:
|
||||
go install golang.org/x/tools/cmd/goimports
|
||||
103
cmd/gorepomod/README.md
Normal file
103
cmd/gorepomod/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# gorepomod
|
||||
|
||||
Helps when you have a git repository with multiple Go modules.
|
||||
|
||||
It handles tasks one might otherwise attempt with
|
||||
|
||||
```
|
||||
find ./ -name "go.mod" | xargs {some hack}
|
||||
```
|
||||
|
||||
Run it from a git repository root.
|
||||
|
||||
It walks the repository, reads `go.mod` files, builds
|
||||
a model of Go modules and intra-repo module
|
||||
dependencies, then performs some operation.
|
||||
|
||||
Install:
|
||||
```
|
||||
go get sigs.k8s.io/kustomize/cmd/gorepomod
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
_Commands that change things (everything but `list`)
|
||||
do nothing but log commands
|
||||
unless you add the `--doIt` flag,
|
||||
allowing the change._
|
||||
|
||||
#### `gorepomod list`
|
||||
|
||||
Lists modules and intra-repo dependencies.
|
||||
|
||||
Use this to get module names for use in other commands.
|
||||
|
||||
#### `gorepomod tidy`
|
||||
|
||||
Creates a change with mechanical updates
|
||||
to `go.mod` and `go.sum` files.
|
||||
|
||||
#### `gorepomod unpin {module}`
|
||||
|
||||
Creates a change to `go.mod` files.
|
||||
|
||||
For each module _m_ in the repository,
|
||||
if _m_ depends on a _{module}_,
|
||||
then _m_'s dependency on it will be replaced by
|
||||
a relative path to the in-repo module.
|
||||
|
||||
#### `gorepomod pin {module} [{version}]`
|
||||
|
||||
Creates a change to `go.mod` files.
|
||||
|
||||
The opposite of `unpin`.
|
||||
|
||||
The change removes replacements and pins _m_ to a
|
||||
specific, previously tagged and released version of _{module}_.
|
||||
|
||||
The argument _{version}_ defaults to recent version of _{module}_.
|
||||
|
||||
_{version}_ should be in semver form, e.g. `v1.2.3`.
|
||||
|
||||
|
||||
#### `gorepomod release {module} [patch|minor|major]`
|
||||
|
||||
Computes a new version for the module, tags the repo
|
||||
with that version, and pushes the tag to the remote.
|
||||
|
||||
The value of the 2nd argument, either `patch` (the default),
|
||||
`minor` or `major`, determines the new version.
|
||||
|
||||
If the existing version is _v1.2.7_, then the new version will be:
|
||||
- `patch` -> _v1.2.8_
|
||||
- `minor` -> _v1.3.0_
|
||||
- `major` -> _v2.0.0_
|
||||
|
||||
After establishing the the version, the command looks for a branch named
|
||||
|
||||
> _release-{module}/-v{major}.{minor}_
|
||||
|
||||
If the branch doesn't exist, the command creates it and pushes it to the remote.
|
||||
|
||||
The command then creates a new tag in the form
|
||||
|
||||
> _{module}/v{major}.{minor}.{patch}_
|
||||
|
||||
The command pushes this tag to the remote. This typically triggers
|
||||
cloud activity to create release artifacts.
|
||||
|
||||
#### `gorepomod unrelease {module}`
|
||||
|
||||
This undoes the work of `release`, by deleting the
|
||||
most recent tag both locally and at the remote.
|
||||
|
||||
You can then fix whatever, and re-release.
|
||||
|
||||
This, however, must be done almost immediately.
|
||||
|
||||
If there's a chance someone (or some cloud robot) already
|
||||
imported the module at the given tag, then don't do this,
|
||||
because it will confuse module caches.
|
||||
|
||||
Do a new patch release instead.
|
||||
|
||||
5
cmd/gorepomod/go.mod
Normal file
5
cmd/gorepomod/go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module sigs.k8s.io/kustomize/cmd/gorepomod
|
||||
|
||||
go 1.15
|
||||
|
||||
require golang.org/x/mod v0.3.0
|
||||
14
cmd/gorepomod/go.sum
Normal file
14
cmd/gorepomod/go.sum
Normal file
@@ -0,0 +1,14 @@
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
195
cmd/gorepomod/internal/arguments/args.go
Normal file
195
cmd/gorepomod/internal/arguments/args.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
doItFlag = "--doIt"
|
||||
cmdPin = "pin"
|
||||
cmdUnPin = "unpin"
|
||||
cmdTidy = "tidy"
|
||||
cmdList = "list"
|
||||
cmdRelease = "release"
|
||||
cmdUnRelease = "unrelease"
|
||||
cmdDebug = "debug"
|
||||
)
|
||||
|
||||
var (
|
||||
commands = []string{
|
||||
cmdPin, cmdUnPin, cmdTidy, cmdList, cmdRelease, cmdUnRelease, cmdDebug}
|
||||
|
||||
// TODO: make this a PATH-like flag
|
||||
// e.g.: --excludes ".git:.idea:site:docs"
|
||||
excSlice = []string{
|
||||
".git",
|
||||
".github",
|
||||
".idea",
|
||||
"docs",
|
||||
"examples",
|
||||
"hack",
|
||||
"site",
|
||||
"releasing",
|
||||
}
|
||||
)
|
||||
|
||||
type Command int
|
||||
|
||||
const (
|
||||
Tidy Command = iota
|
||||
UnPin
|
||||
Pin
|
||||
List
|
||||
Release
|
||||
UnRelease
|
||||
Debug
|
||||
)
|
||||
|
||||
type Args struct {
|
||||
cmd Command
|
||||
moduleName misc.ModuleShortName
|
||||
version semver.SemVer
|
||||
bump semver.SvBump
|
||||
doIt bool
|
||||
}
|
||||
|
||||
func (a *Args) GetCommand() Command {
|
||||
return a.cmd
|
||||
}
|
||||
|
||||
func (a *Args) Bump() semver.SvBump {
|
||||
return a.bump
|
||||
}
|
||||
|
||||
func (a *Args) Version() semver.SemVer {
|
||||
return a.version
|
||||
}
|
||||
|
||||
func (a *Args) ModuleName() misc.ModuleShortName {
|
||||
return a.moduleName
|
||||
}
|
||||
|
||||
func (a *Args) Exclusions() (result []string) {
|
||||
// Make sure the list has no repeats.
|
||||
for k := range utils.SliceToSet(excSlice) {
|
||||
result = append(result, k)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Args) DoIt() bool {
|
||||
return a.doIt
|
||||
}
|
||||
|
||||
type myArgs struct {
|
||||
args []string
|
||||
doIt bool
|
||||
}
|
||||
|
||||
func (a *myArgs) next() (result string) {
|
||||
if !a.more() {
|
||||
panic("no args left")
|
||||
}
|
||||
result = a.args[0]
|
||||
a.args = a.args[1:]
|
||||
return
|
||||
}
|
||||
|
||||
func (a *myArgs) more() bool {
|
||||
return len(a.args) > 0
|
||||
}
|
||||
|
||||
func newArgs() *myArgs {
|
||||
result := &myArgs{}
|
||||
for _, a := range os.Args[1:] {
|
||||
if a == doItFlag {
|
||||
result.doIt = true
|
||||
} else {
|
||||
result.args = append(result.args, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Parse() (result *Args, err error) {
|
||||
result = &Args{}
|
||||
clArgs := newArgs()
|
||||
result.doIt = clArgs.doIt
|
||||
|
||||
result.moduleName = misc.ModuleUnknown
|
||||
if !clArgs.more() {
|
||||
return nil, fmt.Errorf("command needs at least one arg")
|
||||
}
|
||||
command := clArgs.next()
|
||||
switch command {
|
||||
case cmdPin:
|
||||
if !clArgs.more() {
|
||||
return nil, fmt.Errorf("pin needs a moduleName to pin")
|
||||
}
|
||||
result.moduleName = misc.ModuleShortName(clArgs.next())
|
||||
if clArgs.more() {
|
||||
result.version, err = semver.Parse(clArgs.next())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
result.version = semver.Zero()
|
||||
}
|
||||
result.cmd = Pin
|
||||
case cmdUnPin:
|
||||
if !clArgs.more() {
|
||||
return nil, fmt.Errorf("unpin needs a moduleName to unpin")
|
||||
}
|
||||
result.moduleName = misc.ModuleShortName(clArgs.next())
|
||||
result.cmd = UnPin
|
||||
case cmdTidy:
|
||||
result.cmd = Tidy
|
||||
case cmdList:
|
||||
result.cmd = List
|
||||
case cmdRelease:
|
||||
if !clArgs.more() {
|
||||
return nil, fmt.Errorf("specify {module} to release")
|
||||
}
|
||||
result.moduleName = misc.ModuleShortName(clArgs.next())
|
||||
bump := "patch"
|
||||
if clArgs.more() {
|
||||
bump = clArgs.next()
|
||||
}
|
||||
switch bump {
|
||||
case "major":
|
||||
result.bump = semver.Major
|
||||
case "minor":
|
||||
result.bump = semver.Minor
|
||||
case "patch":
|
||||
result.bump = semver.Patch
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"unknown bump %s; specify one of 'major', 'minor' or 'patch'", bump)
|
||||
}
|
||||
result.cmd = Release
|
||||
case cmdUnRelease:
|
||||
if !clArgs.more() {
|
||||
return nil, fmt.Errorf("specify {module} to unrelease")
|
||||
}
|
||||
result.moduleName = misc.ModuleShortName(clArgs.next())
|
||||
result.cmd = UnRelease
|
||||
case cmdDebug:
|
||||
if !clArgs.more() {
|
||||
return nil, fmt.Errorf("specify {module} to debug")
|
||||
}
|
||||
result.moduleName = misc.ModuleShortName(clArgs.next())
|
||||
result.cmd = Debug
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"unknown command %q; must be one of %v", command, commands)
|
||||
}
|
||||
if clArgs.more() {
|
||||
return nil, fmt.Errorf("unknown extra args: %v", clArgs.args)
|
||||
}
|
||||
return
|
||||
}
|
||||
82
cmd/gorepomod/internal/edit/editor.go
Normal file
82
cmd/gorepomod/internal/edit/editor.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package edit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
)
|
||||
|
||||
// Editor runs `go mod` commands on an instance of Module.
|
||||
// If doIt is false, the command is printed, but not run.
|
||||
type Editor struct {
|
||||
module misc.LaModule
|
||||
doIt bool
|
||||
}
|
||||
|
||||
func New(m misc.LaModule, doIt bool) *Editor {
|
||||
return &Editor{
|
||||
doIt: doIt,
|
||||
module: m,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) run(args ...string) error {
|
||||
c := exec.Command(
|
||||
"go",
|
||||
append([]string{"mod"}, args...)...)
|
||||
c.Dir = string(e.module.ShortName())
|
||||
if e.doIt {
|
||||
out, err := c.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s out=%q", err.Error(), out)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("in %-60s; %s\n", c.Dir, c.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func upstairs(depth int) string {
|
||||
var b strings.Builder
|
||||
for i := 0; i < depth; i++ {
|
||||
b.WriteString("../")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (e *Editor) Tidy() error {
|
||||
return e.run("tidy")
|
||||
}
|
||||
|
||||
func (e *Editor) Pin(target misc.LaModule, oldV, newV semver.SemVer) error {
|
||||
err := e.run(
|
||||
"edit",
|
||||
"-dropreplace="+target.ImportPath()+"@"+oldV.String(),
|
||||
"-require="+target.ImportPath()+"@"+newV.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return e.run("tidy")
|
||||
}
|
||||
|
||||
func (e *Editor) UnPin(target misc.LaModule, oldV semver.SemVer) error {
|
||||
var r strings.Builder
|
||||
r.WriteString(target.ImportPath())
|
||||
r.WriteString("@")
|
||||
r.WriteString(oldV.String())
|
||||
r.WriteString("=")
|
||||
r.WriteString(upstairs(e.module.ShortName().Depth()))
|
||||
r.WriteString(string(target.ShortName()))
|
||||
err := e.run(
|
||||
"edit",
|
||||
"-replace="+r.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return e.run("tidy")
|
||||
}
|
||||
32
cmd/gorepomod/internal/edit/editor_test.go
Normal file
32
cmd/gorepomod/internal/edit/editor_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package edit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUpstairs(t *testing.T) {
|
||||
var testCases = map[string]struct {
|
||||
depth int
|
||||
expected string
|
||||
}{
|
||||
"zero": {
|
||||
depth: 0,
|
||||
expected: "",
|
||||
},
|
||||
"one": {
|
||||
depth: 1,
|
||||
expected: "../",
|
||||
},
|
||||
"five": {
|
||||
depth: 5,
|
||||
expected: "../../../../../",
|
||||
},
|
||||
}
|
||||
for n, tc := range testCases {
|
||||
if tc.expected != upstairs(tc.depth) {
|
||||
t.Fatalf(
|
||||
"%s: for depth %d, expected %q, got %q",
|
||||
n, tc.depth, tc.expected, upstairs(tc.depth))
|
||||
}
|
||||
}
|
||||
}
|
||||
75
cmd/gorepomod/internal/gen/main.go
Normal file
75
cmd/gorepomod/internal/gen/main.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
inputFile = "README.md"
|
||||
outputFile = "usage.go"
|
||||
)
|
||||
|
||||
// Convert README.md to a usage function.
|
||||
func main() {
|
||||
inFile, err := os.Open(inputFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer inFile.Close()
|
||||
scanner := bufio.NewScanner(inFile)
|
||||
|
||||
w := NewWriter(outputFile)
|
||||
w.prLn("// Code generated by internal/gen/main.go; DO NOT EDIT.")
|
||||
w.prLn("package main")
|
||||
w.prLn("")
|
||||
w.prLn("")
|
||||
w.prLn("const (")
|
||||
w.prLn(" usageMsg = `")
|
||||
|
||||
// Skip the first two lines.
|
||||
scanner.Scan()
|
||||
scanner.Scan()
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
line = strings.Replace(line, "`", "'", -1)
|
||||
line = strings.Replace(line, "\\[", "[", -1)
|
||||
line = strings.Replace(line, "\\]", "]", -1)
|
||||
w.prLn(line)
|
||||
}
|
||||
w.prLn("`")
|
||||
w.prLn(")")
|
||||
w.close()
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
f *os.File
|
||||
}
|
||||
|
||||
func NewWriter(n string) *writer {
|
||||
f, err := os.Create(n)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create `%s`; %v", n, err)
|
||||
}
|
||||
return &writer{f: f}
|
||||
}
|
||||
|
||||
func (w *writer) prLn(line string) {
|
||||
_, err := w.f.WriteString(line + "\n")
|
||||
if err != nil {
|
||||
log.Printf("Trouble writing: %s", line)
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) close() {
|
||||
if err := w.f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
340
cmd/gorepomod/internal/git/runner.go
Normal file
340
cmd/gorepomod/internal/git/runner.go
Normal file
@@ -0,0 +1,340 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
)
|
||||
|
||||
const (
|
||||
refsTags = "refs/tags/"
|
||||
pathSep = "/"
|
||||
remoteOrigin = misc.TrackedRepo("origin")
|
||||
remoteUpstream = misc.TrackedRepo("upstream")
|
||||
mainBranch = "master"
|
||||
indent = " "
|
||||
doing = " [x] "
|
||||
faking = " [ ] "
|
||||
)
|
||||
|
||||
type safetyLevel int
|
||||
|
||||
const (
|
||||
// Commands that don't hurt, e.g. checking out an existing branch.
|
||||
noHarmDone safetyLevel = iota
|
||||
// Commands that write, and could be hard to undo.
|
||||
undoPainful
|
||||
)
|
||||
|
||||
type Verbosity int
|
||||
|
||||
const (
|
||||
Low Verbosity = iota
|
||||
High
|
||||
)
|
||||
|
||||
var recognizedRemotes = []misc.TrackedRepo{remoteUpstream, remoteOrigin}
|
||||
|
||||
// Runner runs specific git tasks using the git CLI.
|
||||
type Runner struct {
|
||||
// From which directory do we run the commands.
|
||||
workDir string
|
||||
// Run commands, or merely print commands.
|
||||
doIt bool
|
||||
// Run commands, or merely print commands.
|
||||
verbosity Verbosity
|
||||
}
|
||||
|
||||
func NewLoud(wd string, doIt bool) *Runner {
|
||||
return newRunner(wd, doIt, High)
|
||||
}
|
||||
|
||||
func NewQuiet(wd string, doIt bool) *Runner {
|
||||
return newRunner(wd, doIt, Low)
|
||||
}
|
||||
|
||||
func newRunner(wd string, doIt bool, v Verbosity) *Runner {
|
||||
return &Runner{workDir: wd, doIt: doIt, verbosity: v}
|
||||
}
|
||||
|
||||
func (gr *Runner) comment(f string) {
|
||||
if gr.verbosity == Low {
|
||||
return
|
||||
}
|
||||
fmt.Print(indent)
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
func (gr *Runner) doing(s string) {
|
||||
if gr.verbosity == Low {
|
||||
return
|
||||
}
|
||||
fmt.Print(indent)
|
||||
fmt.Print(doing)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
func (gr *Runner) faking(s string) {
|
||||
if gr.verbosity == Low {
|
||||
return
|
||||
}
|
||||
fmt.Print(indent)
|
||||
fmt.Print(faking)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
func (gr *Runner) run(sl safetyLevel, args ...string) (string, error) {
|
||||
c := exec.Command("git", args...)
|
||||
c.Dir = gr.workDir
|
||||
if gr.doIt || sl == noHarmDone {
|
||||
gr.doing(c.String())
|
||||
out, err := c.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(
|
||||
"%s out=%q", err.Error(), strings.TrimSpace(string(out)))
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
gr.faking(c.String())
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (gr *Runner) runNoOut(s safetyLevel, args ...string) error {
|
||||
_, err := gr.run(s, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: allow for other remote names.
|
||||
func (gr *Runner) DetermineRemoteToUse() (misc.TrackedRepo, error) {
|
||||
gr.comment("determining remote to use")
|
||||
out, err := gr.run(noHarmDone, "remote")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
remotes := strings.Split(out, "\n")
|
||||
if len(remotes) < 1 {
|
||||
return "", fmt.Errorf("need at least one remote")
|
||||
}
|
||||
for _, n := range recognizedRemotes {
|
||||
if contains(remotes, n) {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf(
|
||||
"unable to find recognized remote %v", recognizedRemotes)
|
||||
}
|
||||
|
||||
func contains(list []string, item misc.TrackedRepo) bool {
|
||||
for _, n := range list {
|
||||
if n == string(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (gr *Runner) LoadLocalTags() (result misc.VersionMap, err error) {
|
||||
gr.comment("loading local tags")
|
||||
var out string
|
||||
out, err = gr.run(noHarmDone, "tag", "-l")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = make(misc.VersionMap)
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, l := range lines {
|
||||
n, v, err := parseModuleSpec(l)
|
||||
if err != nil {
|
||||
// ignore it
|
||||
continue
|
||||
}
|
||||
result[n] = append(result[n], v)
|
||||
}
|
||||
for _, versions := range result {
|
||||
sort.Sort(versions)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (gr *Runner) LoadRemoteTags(
|
||||
remote misc.TrackedRepo) (result misc.VersionMap, err error) {
|
||||
gr.comment("loading remote tags")
|
||||
var out string
|
||||
out, err = gr.run(noHarmDone, "ls-remote", "--ref", string(remote))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = make(misc.VersionMap)
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, l := range lines {
|
||||
fields := strings.Fields(l)
|
||||
if len(fields) < 2 {
|
||||
// ignore it
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(fields[1], refsTags) {
|
||||
// ignore it
|
||||
continue
|
||||
}
|
||||
path := fields[1][len(refsTags):]
|
||||
n, v, err := parseModuleSpec(path)
|
||||
if err != nil {
|
||||
// ignore it
|
||||
continue
|
||||
}
|
||||
result[n] = append(result[n], v)
|
||||
}
|
||||
for _, versions := range result {
|
||||
sort.Sort(versions)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseModuleSpec(
|
||||
path string) (n misc.ModuleShortName, v semver.SemVer, err error) {
|
||||
fields := strings.Split(path, pathSep)
|
||||
v, err = semver.Parse(fields[len(fields)-1])
|
||||
if err != nil {
|
||||
// Silently ignore versions we don't understand.
|
||||
return "", v, err
|
||||
}
|
||||
n = misc.ModuleAtTop
|
||||
if len(fields) > 1 {
|
||||
n = misc.ModuleShortName(
|
||||
strings.Join(fields[:len(fields)-1], pathSep))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (gr *Runner) Debug(remote misc.TrackedRepo) error {
|
||||
return nil // gr.CheckoutMainBranch(remote)
|
||||
}
|
||||
|
||||
func (gr *Runner) AssureCleanWorkspace() error {
|
||||
gr.comment("assuring a clean workspace")
|
||||
out, err := gr.run(noHarmDone, "status")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.Contains(out, "nothing to commit, working tree clean") {
|
||||
return fmt.Errorf("the workspace isn't clean")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gr *Runner) AssureOnMainBranch() error {
|
||||
gr.comment("assuring main branch checked out")
|
||||
out, err := gr.run(noHarmDone, "status")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.Contains(out, "On branch "+mainBranch) {
|
||||
return fmt.Errorf("expected to be on branch %q", mainBranch)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckoutMainBranch does that.
|
||||
func (gr *Runner) CheckoutMainBranch() error {
|
||||
gr.comment("checking out main branch")
|
||||
return gr.runNoOut(noHarmDone, "checkout", mainBranch)
|
||||
}
|
||||
|
||||
// FetchRemote does that.
|
||||
func (gr *Runner) FetchRemote(remote misc.TrackedRepo) error {
|
||||
gr.comment("fetching remote")
|
||||
return gr.runNoOut(noHarmDone, "fetch", string(remote))
|
||||
}
|
||||
|
||||
// MergeFromRemoteMain does a fast forward only merge with main branch.
|
||||
func (gr *Runner) MergeFromRemoteMain(remote misc.TrackedRepo) error {
|
||||
remo := strings.Join(
|
||||
[]string{string(remote), mainBranch}, pathSep)
|
||||
gr.comment("merging from remote")
|
||||
return gr.runNoOut(undoPainful, "merge", "--ff-only", remo)
|
||||
}
|
||||
|
||||
// CheckoutReleaseBranch attempts to checkout or create a branch.
|
||||
// If it's on the remote already, fail if we cannot check it out locally.
|
||||
func (gr *Runner) CheckoutReleaseBranch(
|
||||
remote misc.TrackedRepo, branch string) error {
|
||||
yes, err := gr.doesRemoteBranchExist(remote, branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if yes {
|
||||
gr.comment("checking out branch")
|
||||
if out, err := gr.run(noHarmDone, "checkout", branch); err != nil {
|
||||
fmt.Printf("error with checkout: %q", err.Error())
|
||||
fmt.Printf("out: %q", out)
|
||||
return fmt.Errorf(
|
||||
"branch %q exists on remote %q, but isn't present locally",
|
||||
branch, string(remote))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
gr.comment("creating branch")
|
||||
// The branch doesn't exist. Create it.
|
||||
out, err := gr.run(noHarmDone, "checkout", "-b", branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.Contains(out, "Switched to a new branch ") {
|
||||
return fmt.Errorf("unexpected branch creation output: %q", out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gr *Runner) doesRemoteBranchExist(
|
||||
remote misc.TrackedRepo, branch string) (bool, error) {
|
||||
gr.comment("looking for branch on remote")
|
||||
out, err := gr.run(noHarmDone, "branch", "-r")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
lookFor := strings.Join([]string{string(remote), branch}, pathSep)
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, l := range lines {
|
||||
if strings.TrimSpace(l) == lookFor {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (gr *Runner) PushBranchToRemote(
|
||||
remote misc.TrackedRepo, branch string) error {
|
||||
gr.comment("pushing branch to remote")
|
||||
return gr.runNoOut(undoPainful, "push", "-f", string(remote), branch)
|
||||
}
|
||||
|
||||
func (gr *Runner) CreateLocalReleaseTag(tag, branch string) error {
|
||||
msg := fmt.Sprintf("\"Release %s on branch %s\"", tag, branch)
|
||||
gr.comment("creating local release tag")
|
||||
return gr.runNoOut(
|
||||
undoPainful,
|
||||
"tag", "-a",
|
||||
"-m", msg,
|
||||
tag)
|
||||
}
|
||||
|
||||
func (gr *Runner) DeleteLocalTag(tag string) error {
|
||||
gr.comment("deleting local tag")
|
||||
return gr.runNoOut(undoPainful, "tag", "--delete", tag)
|
||||
}
|
||||
|
||||
func (gr *Runner) PushTagToRemote(
|
||||
remote misc.TrackedRepo, tag string) error {
|
||||
gr.comment("pushing tag to remote")
|
||||
return gr.runNoOut(undoPainful, "push", string(remote), tag)
|
||||
}
|
||||
|
||||
func (gr *Runner) DeleteTagFromRemote(
|
||||
remote misc.TrackedRepo, tag string) error {
|
||||
gr.comment("deleting tags from remote")
|
||||
return gr.runNoOut(undoPainful, "push", string(remote), ":"+refsTags+tag)
|
||||
}
|
||||
126
cmd/gorepomod/internal/misc/interfaces.go
Normal file
126
cmd/gorepomod/internal/misc/interfaces.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
)
|
||||
|
||||
// ModFunc is a function accepting a module, and returning an error.
|
||||
type ModFunc func(LaModule) error
|
||||
|
||||
type LaRepository interface {
|
||||
// RepoPath is the import of the of repository,
|
||||
// e.g. github.com/kubernetes-sigs/kustomize
|
||||
// The directory {srcRoot}/{importPath} should contain a
|
||||
// dotGit directory.
|
||||
// This directory might be a Go module, or contain directories
|
||||
// that are Go modules, or both.
|
||||
RepoPath() string
|
||||
|
||||
// AbsPath is the full local filesystem path.
|
||||
AbsPath() string
|
||||
|
||||
// FindModule returns a module or nil.
|
||||
FindModule(ModuleShortName) LaModule
|
||||
}
|
||||
|
||||
type LaModule interface {
|
||||
// ShortName is the module's name without the repo.
|
||||
ShortName() ModuleShortName
|
||||
|
||||
// ImportPath is the relative path below the Go src root,
|
||||
// which is the same path as would be used to
|
||||
// import the module.
|
||||
ImportPath() string
|
||||
|
||||
// AbsPath is the absolute path to the module's
|
||||
// go.mod file on the local file system.
|
||||
AbsPath() string
|
||||
|
||||
// Latest version tagged locally.
|
||||
VersionLocal() semver.SemVer
|
||||
|
||||
// Latest version tagged remotely.
|
||||
VersionRemote() semver.SemVer
|
||||
|
||||
// Does this module depend on the argument, and
|
||||
// if so at what version?
|
||||
DependsOn(LaModule) (bool, semver.SemVer)
|
||||
|
||||
// GetReplacements returns a list of replacements.
|
||||
GetReplacements() []string
|
||||
}
|
||||
|
||||
// VersionMap holds the versions associated with modules.
|
||||
type VersionMap map[ModuleShortName]semver.Versions
|
||||
|
||||
func (m VersionMap) Report() {
|
||||
for n, versions := range m {
|
||||
fmt.Println(n)
|
||||
for _, v := range versions {
|
||||
fmt.Print(" ")
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m VersionMap) Latest(
|
||||
n ModuleShortName) semver.SemVer {
|
||||
versions := m[n]
|
||||
if versions == nil {
|
||||
return semver.Zero()
|
||||
}
|
||||
return versions[0]
|
||||
}
|
||||
|
||||
type LesModules []LaModule
|
||||
|
||||
func (s LesModules) LenLongestName() (ans int) {
|
||||
for _, m := range s {
|
||||
l := len(m.ShortName())
|
||||
if l > ans {
|
||||
ans = l
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s LesModules) Apply(f ModFunc) error {
|
||||
for _, m := range s {
|
||||
err := f(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s LesModules) Find(target ModuleShortName) LaModule {
|
||||
for _, m := range s {
|
||||
if m.ShortName() == target {
|
||||
return m
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s LesModules) GetAllThatDependOn(
|
||||
target LaModule) (result TaggedModules) {
|
||||
for _, m := range s {
|
||||
if yes, v := m.DependsOn(target); yes {
|
||||
result = append(result, TaggedModule{M: m, V: v})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s LesModules) InternalDeps(
|
||||
target LaModule) (result TaggedModules) {
|
||||
for _, m := range s {
|
||||
if yes, v := target.DependsOn(m); yes {
|
||||
result = append(result, TaggedModule{M: m, V: v})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
23
cmd/gorepomod/internal/misc/moduleshortname.go
Normal file
23
cmd/gorepomod/internal/misc/moduleshortname.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ModuleShortName is the in-repo path to the directory holding the module
|
||||
// (holding the go.mod file). It's the unique in-repo name of the module.
|
||||
// It's the name used to tag the repo at a particular module version.
|
||||
// E.g. "" (empty), "kyaml", "cmd/config", "plugin/example/whatever".
|
||||
type ModuleShortName string
|
||||
|
||||
// Never used in a tag.
|
||||
const ModuleAtTop = ModuleShortName("{top}")
|
||||
const ModuleUnknown = ModuleShortName("{unknown}")
|
||||
|
||||
func (m ModuleShortName) Depth() int {
|
||||
if m == ModuleAtTop || m == ModuleUnknown {
|
||||
return 0
|
||||
}
|
||||
return strings.Count(string(m), string(filepath.Separator)) + 1
|
||||
}
|
||||
36
cmd/gorepomod/internal/misc/moduleshortname_test.go
Normal file
36
cmd/gorepomod/internal/misc/moduleshortname_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package misc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
)
|
||||
|
||||
func TestDepth(t *testing.T) {
|
||||
var testCases = map[string]struct {
|
||||
path string
|
||||
expectedDepth int
|
||||
}{
|
||||
"zero": {
|
||||
path: "{top}",
|
||||
expectedDepth: 0,
|
||||
},
|
||||
"one": {
|
||||
path: "one",
|
||||
expectedDepth: 1,
|
||||
},
|
||||
"three": {
|
||||
path: "one/two/three",
|
||||
expectedDepth: 3,
|
||||
},
|
||||
}
|
||||
for n, tc := range testCases {
|
||||
m := misc.ModuleShortName(tc.path)
|
||||
d := m.Depth()
|
||||
if d != tc.expectedDepth {
|
||||
t.Fatalf(
|
||||
"%s: %s, expected %d, got %d",
|
||||
n, tc.path, tc.expectedDepth, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
42
cmd/gorepomod/internal/misc/taggedmodule.go
Normal file
42
cmd/gorepomod/internal/misc/taggedmodule.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
)
|
||||
|
||||
// TaggedModule is a module known to be tagged with the given version.
|
||||
type TaggedModule struct {
|
||||
M LaModule
|
||||
V semver.SemVer
|
||||
}
|
||||
|
||||
func (p TaggedModule) String() string {
|
||||
if p.V.IsZero() {
|
||||
return string(p.M.ShortName())
|
||||
}
|
||||
return string(p.M.ShortName()) + "/" + p.V.String()
|
||||
}
|
||||
|
||||
type TaggedModules []TaggedModule
|
||||
|
||||
func (s TaggedModules) String() string {
|
||||
// format := "%-"+strconv.Itoa(s.LenLongestString()+2)+"s"
|
||||
var b strings.Builder
|
||||
for i := range s {
|
||||
b.WriteString(fmt.Sprintf("%-15s", s[i]))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (s TaggedModules) LenLongestString() (ans int) {
|
||||
for _, m := range s {
|
||||
l := len(m.String())
|
||||
if l > ans {
|
||||
ans = l
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
4
cmd/gorepomod/internal/misc/trackedrepo.go
Normal file
4
cmd/gorepomod/internal/misc/trackedrepo.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package misc
|
||||
|
||||
// TrackedRepo identifies a git remote repository.
|
||||
type TrackedRepo string
|
||||
79
cmd/gorepomod/internal/mod/module.go
Normal file
79
cmd/gorepomod/internal/mod/module.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
)
|
||||
|
||||
// Module is an immutable representation of a Go module.
|
||||
type Module struct {
|
||||
repo misc.LaRepository
|
||||
shortName misc.ModuleShortName
|
||||
mf *modfile.File
|
||||
vLocal semver.SemVer
|
||||
vRemote semver.SemVer
|
||||
}
|
||||
|
||||
func New(
|
||||
repo misc.LaRepository,
|
||||
shortName misc.ModuleShortName,
|
||||
mf *modfile.File,
|
||||
vl semver.SemVer,
|
||||
vr semver.SemVer) *Module {
|
||||
return &Module{
|
||||
repo: repo,
|
||||
shortName: shortName,
|
||||
mf: mf,
|
||||
vLocal: vl,
|
||||
vRemote: vr,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Module) GitRepo() misc.LaRepository {
|
||||
return m.repo
|
||||
}
|
||||
|
||||
func (m *Module) VersionLocal() semver.SemVer {
|
||||
return m.vLocal
|
||||
}
|
||||
|
||||
func (m *Module) VersionRemote() semver.SemVer {
|
||||
return m.vRemote
|
||||
}
|
||||
|
||||
func (m *Module) ShortName() misc.ModuleShortName {
|
||||
return m.shortName
|
||||
}
|
||||
|
||||
func (m *Module) ImportPath() string {
|
||||
return filepath.Join(m.repo.RepoPath(), string(m.ShortName()))
|
||||
}
|
||||
|
||||
func (m *Module) AbsPath() string {
|
||||
return filepath.Join(m.repo.AbsPath(), string(m.ShortName()))
|
||||
}
|
||||
|
||||
func (m *Module) DependsOn(target misc.LaModule) (bool, semver.SemVer) {
|
||||
for _, r := range m.mf.Require {
|
||||
if r.Mod.Path == target.ImportPath() {
|
||||
v, err := semver.Parse(r.Mod.Version)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return true, v
|
||||
}
|
||||
}
|
||||
return false, semver.Zero()
|
||||
}
|
||||
|
||||
func (m *Module) GetReplacements() (result []string) {
|
||||
for _, r := range m.mf.Replace {
|
||||
result = append(
|
||||
result, fmt.Sprintf("%s => %s", r.Old.String(), r.New.String()))
|
||||
}
|
||||
return
|
||||
}
|
||||
1
cmd/gorepomod/internal/mod/module_test.go
Normal file
1
cmd/gorepomod/internal/mod/module_test.go
Normal file
@@ -0,0 +1 @@
|
||||
package mod_test
|
||||
134
cmd/gorepomod/internal/repo/dotgitdata.go
Normal file
134
cmd/gorepomod/internal/repo/dotgitdata.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/git"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
dotGitFileName = ".git"
|
||||
srcHint = "/src/"
|
||||
goModFile = "go.mod"
|
||||
)
|
||||
|
||||
// DotGitData holds basic information about a local .git file
|
||||
type DotGitData struct {
|
||||
// srcPath is the absolute path to the local Go src directory.
|
||||
// This used to be $GOPATH/src.
|
||||
// It's the directory containing git repository clones.
|
||||
srcPath string
|
||||
// The path below srcPath to a particular repository
|
||||
// directory, a directory containing a .git directory.
|
||||
// Typically {repoOrg}/{repoUserName}, e.g. sigs.k8s.io/cli-utils
|
||||
repoPath string
|
||||
}
|
||||
|
||||
func (dg *DotGitData) SrcPath() string {
|
||||
return dg.srcPath
|
||||
}
|
||||
|
||||
func (dg *DotGitData) RepoPath() string {
|
||||
return dg.repoPath
|
||||
}
|
||||
|
||||
func (dg *DotGitData) AbsPath() string {
|
||||
return filepath.Join(dg.srcPath, dg.repoPath)
|
||||
}
|
||||
|
||||
// NewDotGitDataFromPath wants the incoming path to hold dotGit
|
||||
// E.g.
|
||||
// ~/gopath/src/sigs.k8s.io/kustomize
|
||||
// ~/gopath/src/github.com/monopole/gorepomod
|
||||
func NewDotGitDataFromPath(path string) (*DotGitData, error) {
|
||||
if !utils.DirExists(filepath.Join(path, dotGitFileName)) {
|
||||
return nil, fmt.Errorf(
|
||||
"%q doesn't have a %q file", path, dotGitFileName)
|
||||
}
|
||||
// This is an attempt to figure out where the user has cloned
|
||||
// their repos. In the old days, it was an import path under
|
||||
// $GOPATH/src. If we cannot guess it, we may need to ask for it,
|
||||
// or maybe proceed without knowing it.
|
||||
index := strings.Index(path, srcHint)
|
||||
if index < 0 {
|
||||
return nil, fmt.Errorf(
|
||||
"path %q doesn't contain %q", path, srcHint)
|
||||
}
|
||||
return &DotGitData{
|
||||
srcPath: path[:index+len(srcHint)-1],
|
||||
repoPath: path[index+len(srcHint):],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// It's a factory factory.
|
||||
func (dg *DotGitData) NewRepoFactory(
|
||||
exclusions []string) (*ManagerFactory, error) {
|
||||
modules, err := loadProtoModules(dg.AbsPath(), exclusions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = dg.checkModules(modules)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runner := git.NewQuiet(dg.AbsPath(), true)
|
||||
remoteName, err := runner.DetermineRemoteToUse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Some tags might exist for modules that
|
||||
// have been renamed or deleted; ignore those.
|
||||
// There might be newer tags locally than remote,
|
||||
// so report both.
|
||||
localTags, err := runner.LoadLocalTags()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteTags, err := runner.LoadRemoteTags(remoteName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ManagerFactory{
|
||||
dg: dg,
|
||||
modules: modules,
|
||||
remoteName: remoteName,
|
||||
versionMapLocal: localTags,
|
||||
versionMapRemote: remoteTags,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (dg *DotGitData) checkModules(modules []*protoModule) error {
|
||||
for _, pm := range modules {
|
||||
|
||||
file := filepath.Join(pm.PathToGoMod(), goModFile)
|
||||
|
||||
// Do the paths make sense?
|
||||
if !strings.HasPrefix(pm.FullPath(), dg.RepoPath()) {
|
||||
return fmt.Errorf(
|
||||
"module %q doesn't start with the repository name %q",
|
||||
pm.FullPath(), dg.RepoPath())
|
||||
}
|
||||
|
||||
shortName := pm.ShortName(dg.RepoPath())
|
||||
if shortName == misc.ModuleAtTop {
|
||||
if pm.PathToGoMod() != dg.AbsPath() {
|
||||
return fmt.Errorf("in %q, problem with top module", file)
|
||||
}
|
||||
} else {
|
||||
// Do the relative path and short name make sense?
|
||||
if !strings.HasSuffix(pm.PathToGoMod(), string(shortName)) {
|
||||
return fmt.Errorf(
|
||||
"in %q, the module name %q doesn't match the file's pathToGoMod %q",
|
||||
file, shortName, pm.PathToGoMod())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
6
cmd/gorepomod/internal/repo/dotgitdata_test.go
Normal file
6
cmd/gorepomod/internal/repo/dotgitdata_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package repo
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLoadTags(t *testing.T) {
|
||||
}
|
||||
194
cmd/gorepomod/internal/repo/manager.go
Normal file
194
cmd/gorepomod/internal/repo/manager.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/edit"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/git"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
|
||||
)
|
||||
|
||||
// Manager manages a git repo.
|
||||
// All data already loaded and validated, it's ready to go.
|
||||
type Manager struct {
|
||||
// Underlying file system facts.
|
||||
dg *DotGitData
|
||||
|
||||
// The remote used for fetching tags, pushing tags,
|
||||
// and pushing release branches.
|
||||
remoteName misc.TrackedRepo
|
||||
|
||||
// The list of known Go modules in the repo.
|
||||
modules misc.LesModules
|
||||
}
|
||||
|
||||
func (mgr *Manager) AbsPath() string {
|
||||
return mgr.dg.AbsPath()
|
||||
}
|
||||
|
||||
func (mgr *Manager) RepoPath() string {
|
||||
return mgr.dg.RepoPath()
|
||||
}
|
||||
|
||||
func (mgr *Manager) FindModule(
|
||||
target misc.ModuleShortName) misc.LaModule {
|
||||
return mgr.modules.Find(target)
|
||||
}
|
||||
|
||||
func (mgr *Manager) Tidy(doIt bool) error {
|
||||
return mgr.modules.Apply(func(m misc.LaModule) error {
|
||||
return edit.New(m, doIt).Tidy()
|
||||
})
|
||||
}
|
||||
|
||||
func (mgr *Manager) Pin(
|
||||
doIt bool, target misc.LaModule, newV semver.SemVer) error {
|
||||
return mgr.modules.Apply(func(m misc.LaModule) error {
|
||||
if yes, oldVersion := m.DependsOn(target); yes {
|
||||
return edit.New(m, doIt).Pin(target, oldVersion, newV)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (mgr *Manager) UnPin(doIt bool, target misc.LaModule) error {
|
||||
return mgr.modules.Apply(func(m misc.LaModule) error {
|
||||
if yes, oldVersion := m.DependsOn(target); yes {
|
||||
return edit.New(m, doIt).UnPin(target, oldVersion)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func hasUnPinnedDeps(m misc.LaModule) string {
|
||||
if len(m.GetReplacements()) > 0 {
|
||||
return "yes"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (mgr *Manager) List() error {
|
||||
fmt.Printf(" src path: %s\n", mgr.dg.SrcPath())
|
||||
fmt.Printf(" repo path: %s\n", mgr.RepoPath())
|
||||
fmt.Printf(" remote: %s\n", mgr.remoteName)
|
||||
format := "%-" +
|
||||
strconv.Itoa(mgr.modules.LenLongestName()+2) +
|
||||
"s%-11s%-11s%17s %s\n"
|
||||
fmt.Printf(
|
||||
format, "NAME", "LOCAL", "REMOTE",
|
||||
"HAS-UNPINNED-DEPS", "INTRA-REPO-DEPENDENCIES")
|
||||
return mgr.modules.Apply(func(m misc.LaModule) error {
|
||||
fmt.Printf(
|
||||
format, m.ShortName(),
|
||||
m.VersionLocal().Pretty(),
|
||||
m.VersionRemote().Pretty(),
|
||||
hasUnPinnedDeps(m),
|
||||
mgr.modules.InternalDeps(m))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func determineBranchAndTag(
|
||||
m misc.LaModule, v semver.SemVer) (string, string) {
|
||||
if m.ShortName() == misc.ModuleAtTop {
|
||||
return fmt.Sprintf("release-%s", v.BranchLabel()), v.String()
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"release-%s-%s", m.ShortName(), v.BranchLabel()),
|
||||
string(m.ShortName()) + "/" + v.String()
|
||||
}
|
||||
|
||||
func (mgr *Manager) Debug(_ misc.LaModule, doIt bool) error {
|
||||
gr := git.NewLoud(mgr.AbsPath(), doIt)
|
||||
return gr.Debug(mgr.remoteName)
|
||||
}
|
||||
|
||||
// Release supports a gitlab flow style release process.
|
||||
//
|
||||
// * All development happens in the branch named "master".
|
||||
// * Each minor release gets its own branch.
|
||||
// *
|
||||
func (mgr *Manager) Release(
|
||||
target misc.LaModule, bump semver.SvBump, doIt bool) error {
|
||||
|
||||
if reps := target.GetReplacements(); len(reps) > 0 {
|
||||
return fmt.Errorf(
|
||||
"to release %q, first pin these replacements: %v",
|
||||
target.ShortName(), reps)
|
||||
}
|
||||
|
||||
newVersion := target.VersionLocal().Bump(bump)
|
||||
|
||||
if newVersion.Equals(target.VersionRemote()) {
|
||||
return fmt.Errorf(
|
||||
"version %s already exists on remote - delete it first", newVersion)
|
||||
}
|
||||
if newVersion.LessThan(target.VersionRemote()) {
|
||||
fmt.Printf(
|
||||
"version %s is less than the most recent remote version (%s)",
|
||||
newVersion, target.VersionRemote())
|
||||
}
|
||||
|
||||
gr := git.NewLoud(mgr.AbsPath(), doIt)
|
||||
|
||||
relBranch, relTag := determineBranchAndTag(target, newVersion)
|
||||
|
||||
fmt.Printf(
|
||||
"Releasing %s, stepping from %s to %s\n",
|
||||
target.ShortName(), target.VersionLocal(), newVersion)
|
||||
|
||||
if err := gr.AssureCleanWorkspace(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.FetchRemote(mgr.remoteName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.CheckoutMainBranch(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.MergeFromRemoteMain(mgr.remoteName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.AssureCleanWorkspace(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.CheckoutReleaseBranch(mgr.remoteName, relBranch); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.MergeFromRemoteMain(mgr.remoteName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.PushBranchToRemote(mgr.remoteName, relBranch); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.CreateLocalReleaseTag(relTag, relBranch); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.PushTagToRemote(mgr.remoteName, relTag); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.CheckoutMainBranch(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mgr *Manager) UnRelease(target misc.LaModule, doIt bool) error {
|
||||
fmt.Printf(
|
||||
"Unreleasing %s/%s\n",
|
||||
target.ShortName(), target.VersionRemote())
|
||||
|
||||
_, tag := determineBranchAndTag(target, target.VersionRemote())
|
||||
|
||||
gr := git.NewLoud(mgr.AbsPath(), doIt)
|
||||
|
||||
if err := gr.DeleteTagFromRemote(mgr.remoteName, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gr.DeleteLocalTag(tag); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
35
cmd/gorepomod/internal/repo/managerfactory.go
Normal file
35
cmd/gorepomod/internal/repo/managerfactory.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/mod"
|
||||
)
|
||||
|
||||
// ManagerFactory is a collection of clean data needed to build
|
||||
// clean, fully wired up instances of Manager.
|
||||
type ManagerFactory struct {
|
||||
dg *DotGitData
|
||||
modules []*protoModule
|
||||
remoteName misc.TrackedRepo
|
||||
versionMapLocal misc.VersionMap
|
||||
versionMapRemote misc.VersionMap
|
||||
}
|
||||
|
||||
func (mf *ManagerFactory) NewRepoManager() *Manager {
|
||||
result := &Manager{
|
||||
dg: mf.dg,
|
||||
remoteName: mf.remoteName,
|
||||
}
|
||||
var modules misc.LesModules
|
||||
for _, pm := range mf.modules {
|
||||
shortName := pm.ShortName(mf.dg.RepoPath())
|
||||
modules = append(
|
||||
modules,
|
||||
mod.New(
|
||||
result, shortName, pm.mf,
|
||||
mf.versionMapLocal.Latest(shortName),
|
||||
mf.versionMapRemote.Latest(shortName)))
|
||||
}
|
||||
result.modules = modules
|
||||
return result
|
||||
}
|
||||
101
cmd/gorepomod/internal/repo/protomodule.go
Normal file
101
cmd/gorepomod/internal/repo/protomodule.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
dotDir = "."
|
||||
)
|
||||
|
||||
// protoModule holds parts being collected to represent a module.
|
||||
type protoModule struct {
|
||||
pathToGoMod string
|
||||
mf *modfile.File
|
||||
}
|
||||
|
||||
func (pm *protoModule) FullPath() string {
|
||||
return pm.mf.Module.Mod.Path
|
||||
}
|
||||
|
||||
func (pm *protoModule) PathToGoMod() string {
|
||||
return pm.pathToGoMod
|
||||
}
|
||||
|
||||
// Represents the trailing version label in a module name.
|
||||
// See https://blog.golang.org/v2-go-modules
|
||||
var trailingVersionPattern = regexp.MustCompile("/v\\d+$")
|
||||
|
||||
func (pm *protoModule) ShortName(
|
||||
repoImportPath string) misc.ModuleShortName {
|
||||
fp := pm.FullPath()
|
||||
if fp == repoImportPath {
|
||||
return misc.ModuleAtTop
|
||||
}
|
||||
p := fp[len(repoImportPath)+1:]
|
||||
stripped := trailingVersionPattern.ReplaceAllString(p, "")
|
||||
return misc.ModuleShortName(stripped)
|
||||
}
|
||||
|
||||
func loadProtoModules(
|
||||
repoRoot string, exclusions []string) (result []*protoModule, err error) {
|
||||
var paths []string
|
||||
paths, err = getPathsToModules(repoRoot, exclusions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, p := range paths {
|
||||
var pm *protoModule
|
||||
pm, err = loadProtoModule(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result = append(result, pm)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func loadProtoModule(path string) (*protoModule, error) {
|
||||
mPath := filepath.Join(path, goModFile)
|
||||
content, err := ioutil.ReadFile(mPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %q: %v\n", mPath, err)
|
||||
}
|
||||
f, err := modfile.Parse(mPath, content, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &protoModule{pathToGoMod: path, mf: f}, nil
|
||||
}
|
||||
|
||||
func getPathsToModules(
|
||||
repoRoot string, exclusions []string) (result []string, err error) {
|
||||
exclusionMap := utils.SliceToSet(exclusions)
|
||||
err = filepath.Walk(
|
||||
repoRoot,
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("trouble at pathToGoMod %q: %v\n", path, err)
|
||||
}
|
||||
if info.IsDir() {
|
||||
if _, ok := exclusionMap[info.Name()]; ok {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if info.Name() == goModFile {
|
||||
result = append(result, path[:len(path)-len(goModFile)-1])
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
47
cmd/gorepomod/internal/repo/protomodule_test.go
Normal file
47
cmd/gorepomod/internal/repo/protomodule_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
)
|
||||
|
||||
func TestShortName(t *testing.T) {
|
||||
var testCases = map[string]struct {
|
||||
name misc.ModuleShortName
|
||||
modFile *modfile.File
|
||||
}{
|
||||
"one": {
|
||||
name: misc.ModuleShortName("garage"),
|
||||
modFile: &modfile.File{
|
||||
Module: &modfile.Module{
|
||||
Mod: module.Version{
|
||||
Path: "gh.com/micheal/garage",
|
||||
Version: "v2.3.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"three": {
|
||||
name: misc.ModuleShortName("fruit/yellow/banana"),
|
||||
modFile: &modfile.File{
|
||||
Module: &modfile.Module{
|
||||
Mod: module.Version{
|
||||
Path: "gh.com/micheal/fruit/yellow/banana",
|
||||
Version: "v2.3.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for n, tc := range testCases {
|
||||
m := protoModule{pathToGoMod: "irrelevant", mf: tc.modFile}
|
||||
actual := m.ShortName("gh.com/micheal")
|
||||
if actual != tc.name {
|
||||
t.Errorf(
|
||||
"%s: expected %s, got %s", n, tc.name, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
98
cmd/gorepomod/internal/semver/semver.go
Normal file
98
cmd/gorepomod/internal/semver/semver.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package semver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SemVer is the immutable semantic version per https://semver.org
|
||||
type SemVer struct {
|
||||
major int
|
||||
minor int
|
||||
patch int
|
||||
}
|
||||
|
||||
func New(major, minor, patch int) SemVer {
|
||||
return SemVer{
|
||||
major: major,
|
||||
minor: minor,
|
||||
patch: patch,
|
||||
}
|
||||
}
|
||||
|
||||
var zero = New(0, 0, 0)
|
||||
|
||||
func Zero() SemVer {
|
||||
return zero
|
||||
}
|
||||
|
||||
// Versions implements sort.Interface to get decreasing order.
|
||||
type Versions []SemVer
|
||||
|
||||
func (v Versions) Len() int { return len(v) }
|
||||
func (v Versions) Less(i, j int) bool { return v[j].LessThan(v[i]) }
|
||||
func (v Versions) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
||||
|
||||
func Parse(raw string) (SemVer, error) {
|
||||
if len(raw) < 6 {
|
||||
// e.g. minimal length is 6, e.g. "v1.2.3"
|
||||
return zero, fmt.Errorf("%q too short to be a version", raw)
|
||||
}
|
||||
if raw[0] != 'v' {
|
||||
return zero, fmt.Errorf("%q must start with letter 'v'", raw)
|
||||
}
|
||||
fields := strings.Split(raw[1:], ".")
|
||||
if len(fields) < 3 {
|
||||
return zero, fmt.Errorf("%q doesn't have the form v1.2.3", raw)
|
||||
}
|
||||
n := make([]int, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
var err error
|
||||
n[i], err = strconv.Atoi(fields[i])
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
}
|
||||
return New(n[0], n[1], n[2]), nil
|
||||
}
|
||||
|
||||
func (v SemVer) Bump(b SvBump) SemVer {
|
||||
switch b {
|
||||
case Major:
|
||||
return New(v.major+1, 0, 0)
|
||||
case Minor:
|
||||
return New(v.major, v.minor+1, 0)
|
||||
default:
|
||||
return New(v.major, v.minor, v.patch+1)
|
||||
}
|
||||
}
|
||||
|
||||
func (v SemVer) BranchLabel() string {
|
||||
return fmt.Sprintf("v%d.%d", v.major, v.minor)
|
||||
}
|
||||
|
||||
func (v SemVer) String() string {
|
||||
return fmt.Sprintf("v%d.%d.%d", v.major, v.minor, v.patch)
|
||||
}
|
||||
|
||||
func (v SemVer) Pretty() string {
|
||||
if v.IsZero() {
|
||||
return ""
|
||||
}
|
||||
return v.String()
|
||||
}
|
||||
|
||||
func (v SemVer) Equals(o SemVer) bool {
|
||||
return v.major == o.major && v.minor == o.minor && v.patch == o.patch
|
||||
}
|
||||
|
||||
func (v SemVer) LessThan(o SemVer) bool {
|
||||
return v.major < o.major ||
|
||||
(v.major == o.major && v.minor < o.minor) ||
|
||||
(v.major == o.major && v.minor == o.minor && v.patch < o.patch)
|
||||
}
|
||||
|
||||
func (v SemVer) IsZero() bool {
|
||||
return v.Equals(zero)
|
||||
}
|
||||
105
cmd/gorepomod/internal/semver/semver_test.go
Normal file
105
cmd/gorepomod/internal/semver/semver_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package semver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
var testCases = map[string]struct {
|
||||
raw string
|
||||
v SemVer
|
||||
errMsg string
|
||||
}{
|
||||
"one": {
|
||||
raw: "v1.2.3",
|
||||
v: SemVer{major: 1, minor: 2, patch: 3},
|
||||
errMsg: "",
|
||||
},
|
||||
"two": {
|
||||
raw: "v2.0.9999",
|
||||
v: SemVer{major: 2, minor: 0, patch: 9999},
|
||||
errMsg: "",
|
||||
},
|
||||
"three": {
|
||||
raw: "pizza",
|
||||
v: zero,
|
||||
errMsg: "\"pizza\" too short to be a version",
|
||||
},
|
||||
"non-digit": {
|
||||
raw: "v1.x.222",
|
||||
v: zero,
|
||||
errMsg: "strconv.Atoi: parsing \"x\": invalid syntax",
|
||||
},
|
||||
"bad fields": {
|
||||
raw: "v1.222",
|
||||
v: zero,
|
||||
errMsg: "\"v1.222\" doesn't have the form v1.2.3",
|
||||
},
|
||||
}
|
||||
for n, tc := range testCases {
|
||||
v, err := Parse(tc.raw)
|
||||
if err == nil {
|
||||
if tc.errMsg != "" {
|
||||
t.Errorf(
|
||||
"%s: no error, but expected err %q", n, tc.errMsg)
|
||||
}
|
||||
if !v.Equals(tc.v) {
|
||||
t.Errorf(
|
||||
"%s: expected %v, got %v", n, tc.v, v)
|
||||
}
|
||||
} else {
|
||||
if tc.errMsg == "" {
|
||||
t.Errorf(
|
||||
"%s: unexpected error %v", n, err)
|
||||
} else {
|
||||
if tc.errMsg != err.Error() {
|
||||
t.Errorf(
|
||||
"%s: expected err msg %q, but got %q",
|
||||
n, tc.errMsg, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessThan(t *testing.T) {
|
||||
var testCases = map[string]struct {
|
||||
v1 SemVer
|
||||
v2 SemVer
|
||||
expected bool
|
||||
}{
|
||||
"one": {
|
||||
v1: SemVer{major: 2, minor: 2, patch: 3},
|
||||
v2: SemVer{major: 1, minor: 2, patch: 3},
|
||||
expected: false,
|
||||
},
|
||||
"two": {
|
||||
v1: SemVer{major: 1, minor: 3, patch: 3},
|
||||
v2: SemVer{major: 1, minor: 2, patch: 3},
|
||||
expected: false,
|
||||
},
|
||||
"three": {
|
||||
v1: SemVer{major: 1, minor: 2, patch: 4},
|
||||
v2: SemVer{major: 1, minor: 2, patch: 3},
|
||||
expected: false,
|
||||
},
|
||||
"eq": {
|
||||
v1: SemVer{major: 2, minor: 2, patch: 3},
|
||||
v2: SemVer{major: 2, minor: 2, patch: 3},
|
||||
expected: false,
|
||||
},
|
||||
"four": {
|
||||
v1: zero,
|
||||
v2: SemVer{major: 0, minor: 0, patch: 1},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for n, tc := range testCases {
|
||||
actual := tc.v1.LessThan(tc.v2)
|
||||
if actual != tc.expected {
|
||||
t.Errorf(
|
||||
"%s: expected %v, got %v for %s LessThan %s",
|
||||
n, tc.expected, actual, tc.v1.String(), tc.v2.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
17
cmd/gorepomod/internal/semver/svbump.go
Normal file
17
cmd/gorepomod/internal/semver/svbump.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package semver
|
||||
|
||||
type SvBump int
|
||||
|
||||
const (
|
||||
Patch SvBump = iota
|
||||
Minor
|
||||
Major
|
||||
)
|
||||
|
||||
func (b SvBump) String() string {
|
||||
return map[SvBump]string{
|
||||
Patch: "Patch",
|
||||
Minor: "Minor",
|
||||
Major: "Major",
|
||||
}[b]
|
||||
}
|
||||
26
cmd/gorepomod/internal/utils/utils.go
Normal file
26
cmd/gorepomod/internal/utils/utils.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func DirExists(name string) bool {
|
||||
info, err := os.Stat(name)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return info.IsDir()
|
||||
}
|
||||
|
||||
func SliceToSet(slice []string) map[string]bool {
|
||||
result := make(map[string]bool)
|
||||
for _, x := range slice {
|
||||
if _, ok := result[x]; ok {
|
||||
log.Fatalf("programmer error - repeated value: %s", x)
|
||||
} else {
|
||||
result[x] = true
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
84
cmd/gorepomod/main.go
Normal file
84
cmd/gorepomod/main.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/arguments"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
|
||||
"sigs.k8s.io/kustomize/cmd/gorepomod/internal/repo"
|
||||
)
|
||||
|
||||
//go:generate go run internal/gen/main.go
|
||||
|
||||
func loadRepoManager(args *arguments.Args) (*repo.Manager, error) {
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dg, err := repo.NewDotGitDataFromPath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pr, err := dg.NewRepoFactory(args.Exclusions())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pr.NewRepoManager(), nil
|
||||
}
|
||||
|
||||
func actualMain() error {
|
||||
args, err := arguments.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mgr, err := loadRepoManager(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var targetModule misc.LaModule = nil
|
||||
if args.ModuleName() != misc.ModuleUnknown {
|
||||
targetModule = mgr.FindModule(args.ModuleName())
|
||||
if targetModule == nil {
|
||||
return fmt.Errorf(
|
||||
"cannot find module %q in repo %s",
|
||||
args.ModuleName(), mgr.RepoPath())
|
||||
}
|
||||
}
|
||||
|
||||
switch args.GetCommand() {
|
||||
case arguments.List:
|
||||
return mgr.List()
|
||||
case arguments.Tidy:
|
||||
return mgr.Tidy(args.DoIt())
|
||||
case arguments.Pin:
|
||||
v := args.Version()
|
||||
if v.IsZero() {
|
||||
v = targetModule.VersionLocal()
|
||||
}
|
||||
return mgr.Pin(args.DoIt(), targetModule, v)
|
||||
case arguments.UnPin:
|
||||
return mgr.UnPin(args.DoIt(), targetModule)
|
||||
case arguments.Release:
|
||||
return mgr.Release(targetModule, args.Bump(), args.DoIt())
|
||||
case arguments.UnRelease:
|
||||
return mgr.UnRelease(targetModule, args.DoIt())
|
||||
case arguments.Debug:
|
||||
return mgr.Debug(targetModule, args.DoIt())
|
||||
default:
|
||||
return fmt.Errorf("cannot handle cmd %v", args.GetCommand())
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Print(usageMsg)
|
||||
return
|
||||
}
|
||||
if err := actualMain(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
109
cmd/gorepomod/usage.go
Normal file
109
cmd/gorepomod/usage.go
Normal file
@@ -0,0 +1,109 @@
|
||||
// Code generated by internal/gen/main.go; DO NOT EDIT.
|
||||
package main
|
||||
|
||||
|
||||
const (
|
||||
usageMsg = `
|
||||
Helps when you have a git repository with multiple Go modules.
|
||||
|
||||
It handles tasks one might otherwise attempt with
|
||||
|
||||
'''
|
||||
find ./ -name "go.mod" | xargs {some hack}
|
||||
'''
|
||||
|
||||
Run it from a git repository root.
|
||||
|
||||
It walks the repository, reads 'go.mod' files, builds
|
||||
a model of Go modules and intra-repo module
|
||||
dependencies, then performs some operation.
|
||||
|
||||
Install:
|
||||
'''
|
||||
go get github.com/monopole/gorepomod
|
||||
'''
|
||||
|
||||
## Usage
|
||||
|
||||
_Commands that change things (everything but 'list')
|
||||
do nothing but log commands
|
||||
unless you add the '--doIt' flag,
|
||||
allowing the change._
|
||||
|
||||
#### 'gorepomod list'
|
||||
|
||||
Lists modules and intra-repo dependencies.
|
||||
|
||||
Use this to get module names for use in other commands.
|
||||
|
||||
#### 'gorepomod tidy'
|
||||
|
||||
Creates a change with mechanical updates
|
||||
to 'go.mod' and 'go.sum' files.
|
||||
|
||||
#### 'gorepomod unpin {module}'
|
||||
|
||||
Creates a change to 'go.mod' files.
|
||||
|
||||
For each module _m_ in the repository,
|
||||
if _m_ depends on a _{module}_,
|
||||
then _m_'s dependency on it will be replaced by
|
||||
a relative path to the in-repo module.
|
||||
|
||||
#### 'gorepomod pin {module} [{version}]'
|
||||
|
||||
Creates a change to 'go.mod' files.
|
||||
|
||||
The opposite of 'unpin'.
|
||||
|
||||
The change removes replacements and pins _m_ to a
|
||||
specific, previously tagged and released version of _{module}_.
|
||||
|
||||
The argument _{version}_ defaults to recent version of _{module}_.
|
||||
|
||||
_{version}_ should be in semver form, e.g. 'v1.2.3'.
|
||||
|
||||
|
||||
#### 'gorepomod release {module} [patch|minor|major]'
|
||||
|
||||
Computes a new version for the module, tags the repo
|
||||
with that version, and pushes the tag to the remote.
|
||||
|
||||
The value of the 2nd argument, either 'patch' (the default),
|
||||
'minor' or 'major', determines the new version.
|
||||
|
||||
If the existing version is _v1.2.7_, then the new version will be:
|
||||
- 'patch' -> _v1.2.8_
|
||||
- 'minor' -> _v1.3.0_
|
||||
- 'major' -> _v2.0.0_
|
||||
|
||||
After establishing the the version, the command looks for a branch named
|
||||
|
||||
> _release-{module}/-v{major}.{minor}_
|
||||
|
||||
If the branch doesn't exist, the command creates it and pushes it to the remote.
|
||||
|
||||
The command then creates a new tag in the form
|
||||
|
||||
> _{module}/v{major}.{minor}.{patch}_
|
||||
|
||||
The command pushes this tag to the remote. This typically triggers
|
||||
cloud activity to create release artifacts.
|
||||
|
||||
#### 'gorepomod unrelease {module}'
|
||||
|
||||
This undoes the work of 'release', by deleting the
|
||||
most recent tag both locally and at the remote.
|
||||
|
||||
You can then fix whatever, and re-release.
|
||||
|
||||
This, however, must be done almost immediately.
|
||||
|
||||
If there's a chance someone (or some cloud robot) already
|
||||
imported the module at the given tag, then don't do this,
|
||||
because it will confuse module caches.
|
||||
|
||||
Do a new patch release instead.
|
||||
|
||||
`
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user