fix conflict

pull/7234/head
zwwhdls 6 years ago
commit 2b796ddade

2
.gitignore vendored

@ -7,3 +7,5 @@
_dist/
bin/
vendor/
# Ignores charts pulled for dependency build tests
cmd/helm/testdata/testcharts/issue-7233/charts/*

@ -0,0 +1,12 @@
To add your organization to this list, simply add your organization's name,
optionally with a link. The list is in alphabetical order.
# Organizations Using Helm
- [Blood Orange](https://bloodorange.io)
- [Microsoft](https://microsoft.com)
- [IBM](https://www.ibm.com)
- [Qovery](https://www.qovery.com/)
- [Samsung SDS](https://www.samsungsds.com/)
[Ville de Montreal](https://montreal.ca)
_This file is part of the CNCF official documentation for projects._

230
KEYS

@ -622,3 +622,233 @@ BlA4kJPTfla4LmKRg/T/xow/naen/aM9mQCs7k2UAoeqNZ6IfQ6G5BZ81H9JNvHC
beriLZDBuRy1LJRjBmZEz+UDBgZoR9oz5DOLh8dGVpkt
=HZO9
-----END PGP PUBLIC KEY BLOCK-----
pub rsa4096 2014-05-13 [SCEA]
ABA2529598F6626C420D335B62F49E747D911B60
uid [ unknown] Matt Butcher <matt.butcher@microsoft.com>
sig 3 62F49E747D911B60 2017-08-11 Matt Butcher <matt.butcher@microsoft.com>
sig 461449C25E36B98E 2018-12-12 Matthew Farina <matt@mattfarina.com>
sig 1EF612347F8A9958 2018-12-12 Adam Reese <adam@reese.io>
sig 2CDBBFBB37AE822A 2018-12-12 Adnan Abdulhussein <prydonius@gmail.com>
uid [ unknown] technosophos (keybase.io/technosophos) <technosophos@gmail.com>
sig 3 62F49E747D911B60 2016-10-24 Matt Butcher <matt.butcher@microsoft.com>
sig 461449C25E36B98E 2018-12-12 Matthew Farina <matt@mattfarina.com>
sig 1EF612347F8A9958 2018-12-12 Adam Reese <adam@reese.io>
sig 2CDBBFBB37AE822A 2018-12-12 Adnan Abdulhussein <prydonius@gmail.com>
uid [ unknown] keybase.io/technosophos <technosophos@keybase.io>
sig 3 62F49E747D911B60 2014-05-13 Matt Butcher <matt.butcher@microsoft.com>
sig 461449C25E36B98E 2018-12-12 Matthew Farina <matt@mattfarina.com>
sig 1EF612347F8A9958 2018-12-12 Adam Reese <adam@reese.io>
sig 2CDBBFBB37AE822A 2018-12-12 Adnan Abdulhussein <prydonius@gmail.com>
sub rsa2048 2014-05-13 [S] [expires: 2022-05-11]
sig 62F49E747D911B60 2014-05-13 Matt Butcher <matt.butcher@microsoft.com>
sub rsa2048 2014-05-13 [E] [expires: 2022-05-11]
sig 62F49E747D911B60 2014-05-13 Matt Butcher <matt.butcher@microsoft.com>
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org
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
=nEJu
-----END PGP PUBLIC KEY BLOCK-----

@ -1,14 +1,16 @@
BINDIR := $(CURDIR)/bin
DIST_DIRS := find * -type d -exec
TARGETS := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
TARGETS := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64
TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-386.tar.gz linux-386.tar.gz.sha256 linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 linux-s390x.tar.gz linux-s390x.tar.gz.sha256 windows-amd64.zip windows-amd64.zip.sha256
BINNAME ?= helm
GOPATH = $(shell go env GOPATH)
DEP = $(GOPATH)/bin/dep
GOX = $(GOPATH)/bin/gox
GOIMPORTS = $(GOPATH)/bin/goimports
ARCH = $(shell uname -p)
ACCEPTANCE_DIR:=$(GOPATH)/src/helm.sh/acceptance-testing
ACCEPTANCE_DIR:=../acceptance-testing
# To specify the subset of acceptance tests to run. '.' means all tests
ACCEPTANCE_RUN_TESTS=.
@ -39,10 +41,13 @@ ifneq ($(BINARY_VERSION),)
LDFLAGS += -X helm.sh/helm/v3/internal/version.version=${BINARY_VERSION}
endif
VERSION_METADATA = unreleased
# Clear the "unreleased" string in BuildMetadata
ifneq ($(GIT_TAG),)
LDFLAGS += -X helm.sh/helm/v3/internal/version.metadata=
VERSION_METADATA =
endif
LDFLAGS += -X helm.sh/helm/v3/internal/version.metadata=${VERSION_METADATA}
LDFLAGS += -X helm.sh/helm/v3/internal/version.gitCommit=${GIT_COMMIT}
LDFLAGS += -X helm.sh/helm/v3/internal/version.gitTreeState=${GIT_DIRTY}
@ -63,7 +68,11 @@ $(BINDIR)/$(BINNAME): $(SRC)
.PHONY: test
test: build
ifeq ($(ARCH),s390x)
test: TESTFLAGS += -v
else
test: TESTFLAGS += -race -v
endif
test: test-style
test: test-unit
@ -138,9 +147,31 @@ dist:
$(DIST_DIRS) zip -r helm-${VERSION}-{}.zip {} \; \
)
.PHONY: fetch-dist
fetch-dist:
mkdir -p _dist
cd _dist && \
for obj in ${TARGET_OBJS} ; do \
curl -sSL -o helm-${VERSION}-$${obj} https://get.helm.sh/helm-${VERSION}-$${obj} ; \
done
.PHONY: sign
sign:
for f in _dist/*.{gz,zip,sha256,sha256sum} ; do \
gpg --armor --detach-sign $${f} ; \
done
# The contents of the .sha256sum file are compatible with tools like
# shasum. For example, using the following command will verify
# the file helm-3.1.0-rc.1-darwin-amd64.tar.gz:
# shasum -a 256 -c helm-3.1.0-rc.1-darwin-amd64.tar.gz.sha256sum
# The .sha256 files hold only the hash and are not compatible with
# verification tools like shasum or sha256sum. This method and file can be
# removed in Helm v4.
.PHONY: checksum
checksum:
for f in _dist/*.{gz,zip} ; do \
shasum -a 256 "$${f}" | sed 's/_dist\///' > "$${f}.sha256sum" ; \
shasum -a 256 "$${f}" | awk '{print $$1}' > "$${f}.sha256" ; \
done

@ -4,6 +4,7 @@ maintainers:
- fibonacci1729
- hickeyma
- jdolitsky
- marckhouzam
- mattfarina
- michelleN
- prydonius

@ -2,14 +2,14 @@
[![CircleCI](https://circleci.com/gh/helm/helm.svg?style=shield)](https://circleci.com/gh/helm/helm)
[![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm)
[![GoDoc](https://godoc.org/helm.sh/helm?status.svg)](https://godoc.org/helm.sh/helm)
[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v3)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3131/badge)](https://bestpractices.coreinfrastructure.org/projects/3131)
Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources.
Use Helm to:
- Find and use [popular software packaged as Helm Charts](https://github.com/helm/charts) to run in Kubernetes
- Find and use [popular software packaged as Helm Charts](https://hub.helm.sh) to run in Kubernetes
- Share your own applications as Helm Charts
- Create reproducible builds of your Kubernetes applications
- Intelligently manage your Kubernetes manifest files

@ -0,0 +1,3 @@
# Helm Security Reporting and Policy
The Helm project has [a common process and policy that can be found here](https://github.com/helm/community/blob/master/SECURITY.md).

@ -139,7 +139,10 @@ __helm_compgen() {
fi
for w in "${completions[@]}"; do
if [[ "${w}" = "$1"* ]]; then
echo "${w}"
# Use printf instead of echo beause it is possible that
# the value to print is -n, which would be interpreted
# as a flag to echo
printf "%s\n" "${w}"
fi
done
}

@ -100,3 +100,16 @@ func TestDependencyBuildCmd(t *testing.T) {
t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v)
}
}
func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) {
chartName := "testdata/testcharts/issue-7233"
cmd := fmt.Sprintf("dependency build '%s'", chartName)
_, out, err := executeActionCommand(cmd)
// Want to make sure the build can verify Helm v2 hash
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
}
}

@ -111,9 +111,9 @@ func TestDependencyUpdateCmd(t *testing.T) {
if _, err := os.Stat(expect); err != nil {
t.Fatalf("Expected %q: %s", expect, err)
}
dontExpect := dir(chartname, "charts/compressedchart-0.1.0.tgz")
if _, err := os.Stat(dontExpect); err == nil {
t.Fatalf("Unexpected %q", dontExpect)
unexpected := dir(chartname, "charts/compressedchart-0.1.0.tgz")
if _, err := os.Stat(unexpected); err == nil {
t.Fatalf("Unexpected %q", unexpected)
}
}
@ -182,7 +182,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
func createTestingMetadata(name, baseURL string) *chart.Chart {
return &chart.Chart{
Metadata: &chart.Metadata{
APIVersion: chart.APIVersionV1,
APIVersion: chart.APIVersionV2,
Name: name,
Version: "1.2.3",
Dependencies: []*chart.Dependency{

@ -19,6 +19,7 @@ package main
import (
"fmt"
"io"
"sort"
"helm.sh/helm/v3/pkg/cli"
@ -55,8 +56,18 @@ type envOptions struct {
}
func (o *envOptions) run(out io.Writer) error {
for k, v := range o.settings.EnvVars() {
fmt.Printf("%s=\"%s\"\n", k, v)
envVars := o.settings.EnvVars()
// Sort the variables by alphabetical order.
// This allows for a constant output across calls to 'helm env'.
var keys []string
for k := range envVars {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s=\"%s\"\n", k, envVars[k])
}
return nil
}

@ -23,15 +23,18 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/cli/values"
"helm.sh/helm/v3/pkg/postrender"
)
const outputFlag = "output"
const postRenderFlag = "post-renderer"
func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL(can specify multiple)")
f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)")
f.StringArrayVar(&v.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&v.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&v.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)")
@ -52,10 +55,19 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
// bindOutputFlag will add the output flag to the given command and bind the
// value to the given format pointer
func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) {
cmd.Flags().VarP(newOutputValue(output.Table, varRef), outputFlag, "o",
f := cmd.Flags()
flag := f.VarPF(newOutputValue(output.Table, varRef), outputFlag, "o",
fmt.Sprintf("prints the output in the specified format. Allowed values: %s", strings.Join(output.Formats(), ", ")))
// Setup shell completion for the flag
cmd.MarkFlagCustom(outputFlag, "__helm_output_options")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
var formatNames []string
for _, format := range output.Formats() {
if strings.HasPrefix(format, toComplete) {
formatNames = append(formatNames, format)
}
}
return formatNames, completion.BashCompDirectiveDefault
})
}
type outputValue output.Format
@ -84,3 +96,31 @@ func (o *outputValue) Set(s string) error {
*o = outputValue(outfmt)
return nil
}
func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) {
cmd.Flags().Var(&postRenderer{varRef}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
}
type postRenderer struct {
renderer *postrender.PostRenderer
}
func (p postRenderer) String() string {
return "exec"
}
func (p postRenderer) Type() string {
return "postrenderer"
}
func (p postRenderer) Set(s string) error {
if s == "" {
return nil
}
pr, err := postrender.NewExec(s)
if err != nil {
return err
}
*p.renderer = pr
return nil
}

@ -0,0 +1,88 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"testing"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/release"
helmtime "helm.sh/helm/v3/pkg/time"
)
func outputFlagCompletionTest(t *testing.T, cmdName string) {
releasesMockWithStatus := func(info *release.Info, hooks ...*release.Hook) []*release.Release {
info.LastDeployed = helmtime.Unix(1452902400, 0).UTC()
return []*release.Release{{
Name: "athos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "porthos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "aramis",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "dartagnan",
Namespace: "gascony",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}}
}
tests := []cmdTestCase{{
name: "completion for output flag long and before arg",
cmd: fmt.Sprintf("__complete %s --output ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for output flag long and after arg",
cmd: fmt.Sprintf("__complete %s aramis --output ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for output flag short and before arg",
cmd: fmt.Sprintf("__complete %s -o ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for output flag short and after arg",
cmd: fmt.Sprintf("__complete %s aramis -o ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}}
runTestCmd(t, tests)
}

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
)
@ -56,8 +57,24 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.IntVar(&client.Version, "revision", 0, "get the named release with revision")
flag := f.Lookup("revision")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) == 1 {
return compListRevisions(cfg, args[0])
}
return nil, completion.BashCompDirectiveNoFileComp
})
f.StringVar(&template, "template", "", "go template for formatting the output, eg: {{.Release.Name}}")
return cmd

@ -41,3 +41,7 @@ func TestGetCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetAllRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get all")
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
)
@ -52,7 +53,23 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
cmd.Flags().IntVar(&client.Version, "revision", 0, "get the named release with revision")
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.IntVar(&client.Version, "revision", 0, "get the named release with revision")
flag := f.Lookup("revision")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) == 1 {
return compListRevisions(cfg, args[0])
}
return nil, completion.BashCompDirectiveNoFileComp
})
return cmd
}

@ -36,3 +36,7 @@ func TestGetHooks(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetHooksRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get hooks")
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
)
@ -52,7 +53,23 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
},
}
cmd.Flags().IntVar(&client.Version, "revision", 0, "get the named release with revision")
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.IntVar(&client.Version, "revision", 0, "get the named release with revision")
flag := f.Lookup("revision")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) == 1 {
return compListRevisions(cfg, args[0])
}
return nil, completion.BashCompDirectiveNoFileComp
})
return cmd
}

@ -36,3 +36,7 @@ func TestGetManifest(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetManifestRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get manifest")
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
)
@ -50,8 +51,23 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.IntVar(&client.Version, "revision", 0, "get the named release with revision")
flag := f.Lookup("revision")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) == 1 {
return compListRevisions(cfg, args[0])
}
return nil, completion.BashCompDirectiveNoFileComp
})
return cmd
}

@ -36,3 +36,7 @@ func TestGetNotesCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetNotesRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get notes")
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
)
@ -54,8 +55,23 @@ func newGetValuesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.IntVar(&client.Version, "revision", 0, "get the named release with revision")
flag := f.Lookup("revision")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) == 1 {
return compListRevisions(cfg, args[0])
}
return nil, completion.BashCompDirectiveNoFileComp
})
f.BoolVarP(&client.AllValues, "all", "a", false, "dump all (computed) values")
bindOutputFlag(cmd, &outfmt)

@ -52,3 +52,11 @@ func TestGetValuesCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetValuesRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get values")
}
func TestGetValuesOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "get values")
}

@ -68,8 +68,7 @@ func main() {
cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:])
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil {
debug("%+v", err)
os.Exit(1)
log.Fatal(err)
}
if err := cmd.Execute(); err != nil {

@ -18,6 +18,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
@ -31,6 +32,7 @@ import (
"helm.sh/helm/v3/internal/test"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage"
@ -47,6 +49,7 @@ func init() {
func runTestCmd(t *testing.T, tests []cmdTestCase) {
t.Helper()
for _, tt := range tests {
for i := 0; i <= tt.repeat; i++ {
t.Run(tt.name, func(t *testing.T) {
defer resetEnv()()
@ -56,7 +59,7 @@ func runTestCmd(t *testing.T, tests []cmdTestCase) {
t.Fatal(err)
}
}
t.Log("running cmd: ", tt.cmd)
t.Logf("running cmd (attempt %d): %s", i+1, tt.cmd)
_, out, err := executeActionCommandC(storage, tt.cmd)
if (err != nil) != tt.wantError {
t.Errorf("expected error, got '%v'", err)
@ -66,6 +69,7 @@ func runTestCmd(t *testing.T, tests []cmdTestCase) {
}
})
}
}
}
func runTestActionCmd(t *testing.T, tests []cmdTestCase) {
@ -93,11 +97,39 @@ func storageFixture() *storage.Storage {
return storage.Init(driver.NewMemory())
}
// go-shellwords does not handle empty arguments properly
// https://github.com/mattn/go-shellwords/issues/5#issuecomment-573431458
//
// This method checks if the last argument was an empty one,
// and if go-shellwords missed it, we add it ourselves.
//
// This is important for completion tests as completion often
// uses an empty last parameter.
func checkLastEmpty(in string, out []string) []string {
lastIndex := len(in) - 1
if lastIndex >= 1 && (in[lastIndex] == '"' && in[lastIndex-1] == '"' ||
in[lastIndex] == '\'' && in[lastIndex-1] == '\'') {
// The last parameter of 'in' was empty ("" or ''), let's make sure it was detected.
if len(out) > 0 && out[len(out)-1] != "" {
// Bug from go-shellwords:
// 'out' does not have the empty parameter. We add it ourselves as a workaround.
out = append(out, "")
} else {
fmt.Println("WARNING: go-shellwords seems to have been fixed. This workaround can be removed.")
}
}
return out
}
func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command, string, error) {
args, err := shellwords.Parse(cmd)
if err != nil {
return nil, "", err
}
// Workaround the bug in shellwords
args = checkLastEmpty(cmd, args)
buf := new(bytes.Buffer)
actionConfig := &action.Configuration{
@ -111,6 +143,9 @@ func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command,
root.SetOutput(buf)
root.SetArgs(args)
if mem, ok := store.Driver.(*driver.Memory); ok {
mem.SetNamespace(settings.Namespace())
}
c, err := root.ExecuteC()
return c, buf.String(), err
@ -124,6 +159,9 @@ type cmdTestCase struct {
wantError bool
// Rels are the available releases at the start of the test.
rels []*release.Release
// Number of repeats (in case a feature was previously flaky and the test checks
// it's now stably producing identical results). 0 means test is run exactly once.
repeat int
}
func executeActionCommand(cmd string) (*cobra.Command, string, error) {
@ -131,14 +169,14 @@ func executeActionCommand(cmd string) (*cobra.Command, string, error) {
}
func resetEnv() func() {
origSettings, origEnv := settings, os.Environ()
origEnv := os.Environ()
return func() {
os.Clearenv()
settings = origSettings
for _, pair := range origEnv {
kv := strings.SplitN(pair, "=", 2)
os.Setenv(kv[0], kv[1])
}
settings = cli.New()
}
}

@ -19,12 +19,14 @@ package main
import (
"fmt"
"io"
"strconv"
"time"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/cli/output"
@ -69,6 +71,14 @@ func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.IntVar(&client.Max, "max", 256, "maximum number of revision to include in history")
bindOutputFlag(cmd, &outfmt)
@ -176,3 +186,16 @@ func min(x, y int) int {
}
return y
}
func compListRevisions(cfg *action.Configuration, releaseName string) ([]string, completion.BashCompDirective) {
client := action.NewHistory(cfg)
var revisions []string
if hist, err := client.Run(releaseName); err == nil {
for _, release := range hist {
revisions = append(revisions, strconv.Itoa(release.Version))
}
return revisions, completion.BashCompDirectiveDefault
}
return nil, completion.BashCompDirectiveError
}

@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"fmt"
"testing"
"helm.sh/helm/v3/pkg/release"
@ -68,3 +69,42 @@ func TestHistoryCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestHistoryOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "history")
}
func revisionFlagCompletionTest(t *testing.T, cmdName string) {
mk := func(name string, vers int, status release.Status) *release.Release {
return release.Mock(&release.MockReleaseOptions{
Name: name,
Version: vers,
Status: status,
})
}
releases := []*release.Release{
mk("musketeers", 11, release.StatusDeployed),
mk("musketeers", 10, release.StatusSuperseded),
mk("musketeers", 9, release.StatusSuperseded),
mk("musketeers", 8, release.StatusSuperseded),
}
tests := []cmdTestCase{{
name: "completion for revision flag",
cmd: fmt.Sprintf("__complete %s musketeers --revision ''", cmdName),
rels: releases,
golden: "output/revision-comp.txt",
}, {
name: "completion for revision flag with too few args",
cmd: fmt.Sprintf("__complete %s --revision ''", cmdName),
rels: releases,
golden: "output/revision-wrong-args-comp.txt",
}, {
name: "completion for revision flag with too many args",
cmd: fmt.Sprintf("__complete %s three musketeers --revision ''", cmdName),
rels: releases,
golden: "output/revision-wrong-args-comp.txt",
}}
runTestCmd(t, tests)
}

@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"fmt"
"io"
"time"
@ -25,6 +26,7 @@ import (
"github.com/spf13/pflag"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
@ -121,8 +123,14 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
return compInstall(args, toComplete, client)
})
addInstallFlags(cmd.Flags(), client, valueOpts)
bindOutputFlag(cmd, &outfmt)
bindPostRenderFlag(cmd, &client.PostRenderer)
return cmd
}
@ -135,8 +143,10 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values
f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)")
f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release")
f.StringVar(&client.Description, "description", "", "add a custom description")
f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored")
f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "run helm dependency update before installing the chart")
f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema")
f.BoolVar(&client.Atomic, "atomic", false, "if set, installation process purges chart on fail. The --wait flag will be set automatically if --atomic is used")
f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present")
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
@ -181,6 +191,10 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options
return nil, err
}
if chartRequested.Metadata.Deprecated {
fmt.Fprintln(out, "WARNING: This chart is deprecated")
}
if req := chartRequested.Metadata.Dependencies; req != nil {
// If CheckDependencies returns an error, we have unfulfilled dependencies.
// As of Helm 2.4.0, this is treated as a stopping condition:
@ -219,3 +233,15 @@ func isChartInstallable(ch *chart.Chart) (bool, error) {
}
return false, errors.Errorf("%s charts are not installable", ch.Metadata.Type)
}
// Provide dynamic auto-completion for the install and template commands
func compInstall(args []string, toComplete string, client *action.Install) ([]string, completion.BashCompDirective) {
requiredArgs := 1
if client.GenerateName {
requiredArgs = 0
}
if len(args) == requiredArgs {
return compListCharts(toComplete, true)
}
return nil, completion.BashCompDirectiveNoFileComp
}

@ -183,7 +183,17 @@ func TestInstall(t *testing.T) {
wantError: true,
golden: "output/subchart-schema-cli-negative.txt",
},
// Install deprecated chart
{
name: "install with warning about deprecated chart",
cmd: "install aeneas testdata/testcharts/deprecated --namespace default",
golden: "output/deprecated-chart.txt",
},
}
runTestActionCmd(t, tests)
}
func TestInstallOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "install")
}

@ -19,6 +19,8 @@ package main
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
@ -51,6 +53,21 @@ func newLintCmd(out io.Writer) *cobra.Command {
if len(args) > 0 {
paths = args
}
if client.WithSubcharts {
for _, p := range paths {
filepath.Walk(filepath.Join(p, "charts"), func(path string, info os.FileInfo, err error) error {
if info != nil {
if info.Name() == "Chart.yaml" {
paths = append(paths, filepath.Dir(path))
} else if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") {
paths = append(paths, path)
}
}
return nil
})
}
}
client.Namespace = settings.Namespace()
vals, err := valueOpts.MergeValues(getter.All(settings))
if err != nil {
@ -102,6 +119,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
f := cmd.Flags()
f.BoolVar(&client.Strict, "strict", false, "fail on lint warnings")
f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts")
addValueOptionsFlags(f, valueOpts)
return cmd

@ -0,0 +1,38 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"testing"
)
func TestLintCmdWithSubchartsFlag(t *testing.T) {
testChart := "testdata/testcharts/chart-with-bad-subcharts"
tests := []cmdTestCase{{
name: "lint good chart with bad subcharts",
cmd: fmt.Sprintf("lint %s", testChart),
golden: "output/lint-chart-with-bad-subcharts.txt",
wantError: false,
}, {
name: "lint good chart with bad subcharts using --with-subcharts flag",
cmd: fmt.Sprintf("lint --with-subcharts %s", testChart),
golden: "output/lint-chart-with-bad-subcharts-with-subcharts.txt",
wantError: true,
}}
runTestCmd(t, tests)
}

@ -26,13 +26,14 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/release"
)
var listHelp = `
This command lists all of the releases.
This command lists all of the releases for a specified namespace (uses current namespace context if namespace not specified).
By default, it lists only releases that are deployed or failed. Flags like
'--uninstalled' and '--all' will alter this behavior. Such flags can be combined:
@ -96,8 +97,8 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVarP(&client.Short, "short", "q", false, "output short (quiet) listing format")
f.BoolVarP(&client.ByDate, "date", "d", false, "sort by release date")
f.BoolVarP(&client.SortReverse, "reverse", "r", false, "reverse the sort order")
f.BoolVarP(&client.All, "all", "a", false, "show all releases, not just the ones marked deployed or failed")
f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases")
f.BoolVarP(&client.All, "all", "a", false, "show all releases without any filter applied")
f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases (if 'helm uninstall --keep-history' was used)")
f.BoolVar(&client.Superseded, "superseded", false, "show superseded releases")
f.BoolVar(&client.Uninstalling, "uninstalling", false, "show releases that are currently being uninstalled")
f.BoolVar(&client.Deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled")
@ -164,3 +165,26 @@ func (r *releaseListWriter) WriteJSON(out io.Writer) error {
func (r *releaseListWriter) WriteYAML(out io.Writer) error {
return output.EncodeYAML(out, r.releases)
}
// Provide dynamic auto-completion for release names
func compListReleases(toComplete string, cfg *action.Configuration) ([]string, completion.BashCompDirective) {
completion.CompDebugln(fmt.Sprintf("compListReleases with toComplete %s", toComplete))
client := action.NewList(cfg)
client.All = true
client.Limit = 0
client.Filter = fmt.Sprintf("^%s", toComplete)
client.SetStateMask()
results, err := client.Run()
if err != nil {
return nil, completion.BashCompDirectiveDefault
}
var choices []string
for _, res := range results {
choices = append(choices, res.Name)
}
return choices, completion.BashCompDirectiveNoFileComp
}

@ -131,6 +131,16 @@ func TestListCmd(t *testing.T) {
},
Chart: chartInfo,
},
{
Name: "starlord",
Version: 2,
Namespace: "milano",
Info: &release.Info{
LastDeployed: timestamp1,
Status: release.StatusDeployed,
},
Chart: chartInfo,
},
}
tests := []cmdTestCase{{
@ -203,6 +213,15 @@ func TestListCmd(t *testing.T) {
cmd: "list --uninstalling",
golden: "output/list-uninstalling.txt",
rels: releaseFixture,
}, {
name: "list releases in another namespace",
cmd: "list -n milano",
golden: "output/list-namespace.txt",
rels: releaseFixture,
}}
runTestCmd(t, tests)
}
func TestListOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "list")
}

@ -151,8 +151,11 @@ func manuallyProcessArgs(args []string) ([]string, []string) {
case "--debug":
known = append(known, a)
case isKnown(a):
known = append(known, a, args[i+1])
known = append(known, a)
i++
if i < len(args) {
known = append(known, args[i])
}
default:
if knownArg(a) {
known = append(known, a)

@ -20,6 +20,7 @@ import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/pkg/errors"
@ -36,10 +37,15 @@ This command packages a chart into a versioned chart archive file. If a path
is given, this will look at that path for a chart (which must contain a
Chart.yaml file) and then package that directory.
If no path is given, this will look in the present working directory for a
Chart.yaml file, and (if found) build the current directory into a chart.
Versioned chart archives are used by Helm package repositories.
To sign a chart, use the '--sign' flag. In most cases, you should also
provide '--keyring path/to/secret/keys' and '--key keyname'.
$ helm package --sign ./mychart --key mykey --keyring ~/.gnupg/secring.gpg
If '--keyring' is not specified, Helm usually defaults to the public keyring
unless your environment is otherwise configured.
`
func newPackageCmd(out io.Writer) *cobra.Command {
@ -75,6 +81,9 @@ func newPackageCmd(out io.Writer) *cobra.Command {
if err != nil {
return err
}
if _, err := os.Stat(args[i]); err != nil {
return err
}
if client.DependencyUpdate {
downloadManager := &downloader.Manager{
@ -109,7 +118,6 @@ func newPackageCmd(out io.Writer) *cobra.Command {
f.StringVar(&client.AppVersion, "app-version", "", "set the appVersion on the chart to this version")
f.StringVarP(&client.Destination, "destination", "d", ".", "location to write the chart.")
f.BoolVarP(&client.DependencyUpdate, "dependency-update", "u", false, `update dependencies from "Chart.yaml" to dir "charts/" before packaging`)
addValueOptionsFlags(f, valueOpts)
return cmd
}

@ -17,13 +17,9 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"testing"
"github.com/spf13/cobra"
@ -31,15 +27,9 @@ import (
"helm.sh/helm/v3/internal/test/ensure"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
)
func TestPackage(t *testing.T) {
statFileMsg := "no such file or directory"
if runtime.GOOS == "windows" {
statFileMsg = "The system cannot find the file specified."
}
tests := []struct {
name string
flags map[string]string
@ -108,13 +98,6 @@ func TestPackage(t *testing.T) {
hasfile: "chart-missing-deps-0.1.0.tgz",
err: true,
},
{
name: "package --values does-not-exist",
args: []string{"testdata/testcharts/alpine"},
flags: map[string]string{"values": "does-not-exist"},
expect: fmt.Sprintf("does-not-exist: %s", statFileMsg),
err: true,
},
{
name: "package testdata/testcharts/chart-bad-type",
args: []string{"testdata/testcharts/chart-bad-type"},
@ -213,124 +196,6 @@ func TestSetAppVersion(t *testing.T) {
}
}
func TestPackageValues(t *testing.T) {
defer resetEnv()()
repoFile := "testdata/helmhome/helm/repositories.yaml"
testCases := []struct {
desc string
args []string
valuefilesContents []string
flags map[string]string
expected []string
}{
{
desc: "helm package, single values file",
args: []string{"testdata/testcharts/alpine"},
flags: map[string]string{"repository-config": repoFile},
valuefilesContents: []string{"Name: chart-name-foo"},
expected: []string{"Name: chart-name-foo"},
},
{
desc: "helm package, multiple values files",
args: []string{"testdata/testcharts/alpine"},
flags: map[string]string{"repository-config": repoFile},
valuefilesContents: []string{"Name: chart-name-foo", "foo: bar"},
expected: []string{"Name: chart-name-foo", "foo: bar"},
},
{
desc: "helm package, with set option",
args: []string{"testdata/testcharts/alpine"},
flags: map[string]string{"set": "Name=chart-name-foo", "repository-config": repoFile},
expected: []string{"Name: chart-name-foo"},
},
{
desc: "helm package, set takes precedence over value file",
args: []string{"testdata/testcharts/alpine"},
valuefilesContents: []string{"Name: chart-name-foo"},
flags: map[string]string{"set": "Name=chart-name-bar", "repository-config": repoFile},
expected: []string{"Name: chart-name-bar"},
},
}
for _, tc := range testCases {
var files []string
for _, contents := range tc.valuefilesContents {
f := createValuesFile(t, contents)
files = append(files, f)
}
valueFiles := strings.Join(files, ",")
expected, err := chartutil.ReadValues([]byte(strings.Join(tc.expected, "\n")))
if err != nil {
t.Errorf("unexpected error parsing values: %q", err)
}
outputDir := ensure.TempDir(t)
if len(tc.flags) == 0 {
tc.flags = make(map[string]string)
}
tc.flags["destination"] = outputDir
if len(valueFiles) > 0 {
tc.flags["values"] = valueFiles
}
cmd := newPackageCmd(&bytes.Buffer{})
setFlags(cmd, tc.flags)
if err := cmd.RunE(cmd, tc.args); err != nil {
t.Fatalf("unexpected error: %q", err)
}
outputFile := filepath.Join(outputDir, "alpine-0.1.0.tgz")
verifyOutputChartExists(t, outputFile)
actual, err := getChartValues(outputFile)
if err != nil {
t.Fatalf("unexpected error extracting chart values: %q", err)
}
verifyValues(t, actual, expected)
}
}
func createValuesFile(t *testing.T, data string) string {
outputDir := ensure.TempDir(t)
outputFile := filepath.Join(outputDir, "values.yaml")
if err := ioutil.WriteFile(outputFile, []byte(data), 0644); err != nil {
t.Fatalf("err: %s", err)
}
return outputFile
}
func getChartValues(chartPath string) (chartutil.Values, error) {
chart, err := loader.Load(chartPath)
if err != nil {
return nil, err
}
return chart.Values, nil
}
func verifyValues(t *testing.T, actual, expected chartutil.Values) {
t.Helper()
for key, value := range expected.AsMap() {
if got := actual[key]; got != value {
t.Errorf("Expected %q, got %q (%v)", value, got, actual)
}
}
}
func verifyOutputChartExists(t *testing.T, chartPath string) {
if chartFile, err := os.Stat(chartPath); err != nil {
t.Errorf("expected file %q, got err %q", chartPath, err)
} else if chartFile.Size() == 0 {
t.Errorf("file %q has zero bytes.", chartPath)
}
}
func setFlags(cmd *cobra.Command, flags map[string]string) {
dest := cmd.Flags()
for f, v := range flags {

@ -18,6 +18,7 @@ package main
import (
"fmt"
"io"
"strings"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
@ -46,3 +47,17 @@ func newPluginListCmd(out io.Writer) *cobra.Command {
}
return cmd
}
// Provide dynamic auto-completion for plugin names
func compListPlugins(toComplete string) []string {
var pNames []string
plugins, err := findPlugins(settings.PluginsDirectory)
if err == nil {
for _, p := range plugins {
if strings.HasPrefix(p.Metadata.Name, toComplete) {
pNames = append(pNames, p.Metadata.Name)
}
}
}
return pNames
}

@ -24,6 +24,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/plugin"
)
@ -33,6 +34,7 @@ type pluginUninstallOptions struct {
func newPluginUninstallCmd(out io.Writer) *cobra.Command {
o := &pluginUninstallOptions{}
cmd := &cobra.Command{
Use: "uninstall <plugin>...",
Aliases: []string{"rm", "remove"},
@ -44,6 +46,15 @@ func newPluginUninstallCmd(out io.Writer) *cobra.Command {
return o.run(out)
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListPlugins(toComplete), completion.BashCompDirectiveNoFileComp
})
return cmd
}

@ -24,6 +24,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/plugin"
"helm.sh/helm/v3/pkg/plugin/installer"
)
@ -34,6 +35,7 @@ type pluginUpdateOptions struct {
func newPluginUpdateCmd(out io.Writer) *cobra.Command {
o := &pluginUpdateOptions{}
cmd := &cobra.Command{
Use: "update <plugin>...",
Aliases: []string{"up"},
@ -45,6 +47,15 @@ func newPluginUpdateCmd(out io.Writer) *cobra.Command {
return o.run(out)
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListPlugins(toComplete), completion.BashCompDirectiveNoFileComp
})
return cmd
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
)
@ -68,6 +69,14 @@ func newPullCmd(out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListCharts(toComplete, false)
})
f := cmd.Flags()
f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.BoolVar(&client.Untar, "untar", false, "if set to true, will untar the chart after downloading it")

@ -41,7 +41,10 @@ func TestPullCmd(t *testing.T) {
tests := []struct {
name string
args string
existFile string
existDir string
wantError bool
wantErrorMsg string
failExpect string
expectFile string
expectDir bool
@ -87,10 +90,24 @@ func TestPullCmd(t *testing.T) {
expectFile: "./signtest",
expectDir: true,
},
{
name: "Fetch untar when file with same name existed",
args: "test/test1 --untar --untardir test1",
existFile: "test1",
wantError: true,
wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "test1")),
},
{
name: "Fetch untar when dir with same name existed",
args: "test/test2 --untar --untardir test2",
existDir: "test2",
wantError: true,
wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "test2")),
},
{
name: "Fetch, verify, untar",
args: "test/signtest --verify --keyring=testdata/helm-test-key.pub --untar --untardir signtest",
expectFile: "./signtest",
args: "test/signtest --verify --keyring=testdata/helm-test-key.pub --untar --untardir signtest2",
expectFile: "./signtest2",
expectDir: true,
expectVerify: true,
},
@ -127,9 +144,27 @@ func TestPullCmd(t *testing.T) {
filepath.Join(outdir, "repositories.yaml"),
outdir,
)
// Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182
if tt.existFile != "" {
file := filepath.Join(outdir, tt.existFile)
_, err := os.Create(file)
if err != nil {
t.Fatal("err")
}
}
if tt.existDir != "" {
file := filepath.Join(outdir, tt.existDir)
err := os.Mkdir(file, 0755)
if err != nil {
t.Fatal(err)
}
}
_, out, err := executeActionCommand(cmd)
if err != nil {
if tt.wantError {
if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() {
t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg)
}
return
}
t.Fatalf("%q reported error: %s", tt.name, err)

@ -24,6 +24,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
)
@ -71,6 +72,14 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&outputLogs, "logs", false, "Dump the logs from test pods (this runs after all tests are complete, but before any cleanup)")

@ -29,7 +29,7 @@ import (
"github.com/gofrs/flock"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"sigs.k8s.io/yaml"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/getter"

@ -19,13 +19,16 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"testing"
"gopkg.in/yaml.v2"
"sigs.k8s.io/yaml"
"helm.sh/helm/v3/internal/test/ensure"
"helm.sh/helm/v3/pkg/helmpath"
"helm.sh/helm/v3/pkg/helmpath/xdg"
"helm.sh/helm/v3/pkg/repo"
"helm.sh/helm/v3/pkg/repo/repotest"
)
@ -55,7 +58,8 @@ func TestRepoAdd(t *testing.T) {
}
defer ts.Stop()
repoFile := filepath.Join(ensure.TempDir(t), "repositories.yaml")
rootDir := ensure.TempDir(t)
repoFile := filepath.Join(rootDir, "repositories.yaml")
const testRepoName = "test-name"
@ -65,6 +69,7 @@ func TestRepoAdd(t *testing.T) {
noUpdate: true,
repoFile: repoFile,
}
os.Setenv(xdg.CacheHomeEnvVar, rootDir)
if err := o.run(ioutil.Discard); err != nil {
t.Error(err)
@ -79,6 +84,15 @@ func TestRepoAdd(t *testing.T) {
t.Errorf("%s was not successfully inserted into %s", testRepoName, repoFile)
}
idx := filepath.Join(helmpath.CachePath("repository"), helmpath.CacheIndexFile(testRepoName))
if _, err := os.Stat(idx); os.IsNotExist(err) {
t.Errorf("Error cache index file was not created for repository %s", testRepoName)
}
idx = filepath.Join(helmpath.CachePath("repository"), helmpath.CacheChartsFile(testRepoName))
if _, err := os.Stat(idx); os.IsNotExist(err) {
t.Errorf("Error cache charts file was not created for repository %s", testRepoName)
}
o.noUpdate = false
if err := o.run(ioutil.Discard); err != nil {

@ -119,7 +119,7 @@ func TestRepoIndexCmd(t *testing.T) {
t.Error(err)
}
_, err = repo.LoadIndexFile(destIndex)
index, err = repo.LoadIndexFile(destIndex)
if err != nil {
t.Fatal(err)
}
@ -130,8 +130,8 @@ func TestRepoIndexCmd(t *testing.T) {
}
vs = index.Entries["compressedchart"]
if len(vs) != 3 {
t.Errorf("expected 3 versions, got %d: %#v", len(vs), vs)
if len(vs) != 1 {
t.Errorf("expected 1 versions, got %d: %#v", len(vs), vs)
}
expectedVersion = "0.3.0"

@ -18,6 +18,7 @@ package main
import (
"io"
"strings"
"github.com/gosuri/uitable"
"github.com/pkg/errors"
@ -95,3 +96,18 @@ func (r *repoListWriter) encodeByFormat(out io.Writer, format output.Format) err
// WriteJSON and WriteYAML, we shouldn't get invalid types
return nil
}
// Provide dynamic auto-completion for repo names
func compListRepos(prefix string) []string {
var rNames []string
f, err := repo.LoadFile(settings.RepositoryConfig)
if err == nil && len(f.Repositories) > 0 {
for _, repo := range f.Repositories {
if strings.HasPrefix(repo.Name, prefix) {
rNames = append(rNames, repo.Name)
}
}
}
return rNames
}

@ -0,0 +1,25 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"testing"
)
func TestRepoListOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "repo list")
}

@ -26,6 +26,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/helmpath"
"helm.sh/helm/v3/pkg/repo"
)
@ -38,6 +39,7 @@ type repoRemoveOptions struct {
func newRepoRemoveCmd(out io.Writer) *cobra.Command {
o := &repoRemoveOptions{}
cmd := &cobra.Command{
Use: "remove [NAME]",
Aliases: []string{"rm"},
@ -51,6 +53,14 @@ func newRepoRemoveCmd(out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListRepos(toComplete), completion.BashCompDirectiveNoFileComp
})
return cmd
}
@ -76,7 +86,12 @@ func (o *repoRemoveOptions) run(out io.Writer) error {
}
func removeRepoCache(root, name string) error {
idx := filepath.Join(root, helmpath.CacheIndexFile(name))
idx := filepath.Join(root, helmpath.CacheChartsFile(name))
if _, err := os.Stat(idx); err == nil {
os.Remove(idx)
}
idx = filepath.Join(root, helmpath.CacheIndexFile(name))
if _, err := os.Stat(idx); os.IsNotExist(err) {
return nil
} else if err != nil {

@ -63,10 +63,13 @@ func TestRepoRemove(t *testing.T) {
}
idx := filepath.Join(rootDir, helmpath.CacheIndexFile(testRepoName))
mf, _ := os.Create(idx)
mf.Close()
idx2 := filepath.Join(rootDir, helmpath.CacheChartsFile(testRepoName))
mf, _ = os.Create(idx2)
mf.Close()
b.Reset()
if err := rmOpts.run(b); err != nil {
@ -77,7 +80,11 @@ func TestRepoRemove(t *testing.T) {
}
if _, err := os.Stat(idx); err == nil {
t.Errorf("Error cache file was not removed for repository %s", testRepoName)
t.Errorf("Error cache index file was not removed for repository %s", testRepoName)
}
if _, err := os.Stat(idx2); err == nil {
t.Errorf("Error cache chart file was not removed for repository %s", testRepoName)
}
f, err := repo.LoadFile(repoFile)

@ -25,6 +25,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
)
@ -64,6 +65,14 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.Flags()
f.BoolVar(&client.DryRun, "dry-run", false, "simulate a rollback")
f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")

@ -23,55 +23,16 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/internal/experimental/registry"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
)
const (
bashCompletionFunc = `
__helm_override_flag_list=(--kubeconfig --kube-context --namespace -n)
__helm_override_flags()
{
local ${__helm_override_flag_list[*]##*-} two_word_of of var
for w in "${words[@]}"; do
if [ -n "${two_word_of}" ]; then
eval "${two_word_of##*-}=\"${two_word_of}=\${w}\""
two_word_of=
continue
fi
for of in "${__helm_override_flag_list[@]}"; do
case "${w}" in
${of}=*)
eval "${of##*-}=\"${w}\""
;;
${of})
two_word_of="${of}"
;;
esac
done
done
for var in "${__helm_override_flag_list[@]##*-}"; do
if eval "test -n \"\$${var}\""; then
eval "echo \${${var}}"
fi
done
}
__helm_override_flags_to_kubectl_flags()
{
# --kubeconfig, -n, --namespace stay the same for kubectl
# --kube-context becomes --context for kubectl
__helm_debug "${FUNCNAME[0]}: flags to convert: $1"
echo "$1" | sed s/kube-context/context/
}
__helm_get_repos()
{
eval $(__helm_binary_name) repo list 2>/dev/null | tail +2 | cut -f1
}
contextCompFunc = `
__helm_get_contexts()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
@ -81,219 +42,6 @@ __helm_get_contexts()
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_get_namespaces()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local template out
template="{{ range .items }}{{ .metadata.name }} {{ end }}"
flags=$(__helm_override_flags_to_kubectl_flags "$(__helm_override_flags)")
__helm_debug "${FUNCNAME[0]}: override flags for kubectl are: $flags"
# Must use eval in case the flags contain a variable such as $HOME
if out=$(eval kubectl get ${flags} -o template --template=\"${template}\" namespace 2>/dev/null); then
COMPREPLY+=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_output_options()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
COMPREPLY+=( $( compgen -W "%[1]s" -- "$cur" ) )
}
__helm_binary_name()
{
local helm_binary
helm_binary="${words[0]}"
__helm_debug "${FUNCNAME[0]}: helm_binary is ${helm_binary}"
echo ${helm_binary}
}
# This function prevents the zsh shell from adding a space after
# a completion by adding a second, fake completion
__helm_zsh_comp_nospace() {
__helm_debug "${FUNCNAME[0]}: in is ${in[*]}"
local out in=("$@")
# The shell will normally add a space after these completions.
# To avoid that we should use "compopt -o nospace". However, it is not
# available in zsh.
# Instead, we trick the shell by pretending there is a second, longer match.
# We only do this if there is a single choice left for completion
# to reduce the times the user could be presented with the fake completion choice.
out=($(echo ${in[*]} | tr " " "\n" | \grep "^${cur}"))
__helm_debug "${FUNCNAME[0]}: out is ${out[*]}"
[ ${#out[*]} -eq 1 ] && out+=("${out}.")
__helm_debug "${FUNCNAME[0]}: out is now ${out[*]}"
echo "${out[*]}"
}
# $1 = 1 if the completion should include local charts (which means file completion)
__helm_list_charts()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local repo url file out=() nospace=0 wantFiles=$1
# Handle completions for repos
for repo in $(__helm_get_repos); do
if [[ "${cur}" =~ ^${repo}/.* ]]; then
# We are doing completion from within a repo
out=$(eval $(__helm_binary_name) search repo ${cur} 2>/dev/null | cut -f1 | \grep ^${cur})
nospace=0
elif [[ ${repo} =~ ^${cur}.* ]]; then
# We are completing a repo name
out+=(${repo}/)
nospace=1
fi
done
__helm_debug "${FUNCNAME[0]}: out after repos is ${out[*]}"
# Handle completions for url prefixes
for url in https:// http:// file://; do
if [[ "${cur}" =~ ^${url}.* ]]; then
# The user already put in the full url prefix. Return it
# back as a completion to avoid the shell doing path completion
out="${cur}"
nospace=1
elif [[ ${url} =~ ^${cur}.* ]]; then
# We are completing a url prefix
out+=(${url})
nospace=1
fi
done
__helm_debug "${FUNCNAME[0]}: out after urls is ${out[*]}"
# Handle completion for files.
# We only do this if:
# 1- There are other completions found (if there are no completions,
# the shell will do file completion itself)
# 2- If there is some input from the user (or else we will end up
# listing the entire content of the current directory which will
# be too many choices for the user to find the real repos)
if [ $wantFiles -eq 1 ] && [ -n "${out[*]}" ] && [ -n "${cur}" ]; then
for file in $(\ls); do
if [[ ${file} =~ ^${cur}.* ]]; then
# We are completing a file prefix
out+=(${file})
nospace=1
fi
done
fi
__helm_debug "${FUNCNAME[0]}: out after files is ${out[*]}"
# If the user didn't provide any input to completion,
# we provide a hint that a path can also be used
[ $wantFiles -eq 1 ] && [ -z "${cur}" ] && out+=(./ /)
__helm_debug "${FUNCNAME[0]}: out after checking empty input is ${out[*]}"
if [ $nospace -eq 1 ]; then
if [[ -n "${ZSH_VERSION}" ]]; then
# Don't let the shell add a space after the completion
local tmpout=$(__helm_zsh_comp_nospace "${out[@]}")
unset out
out=$tmpout
elif [[ $(type -t compopt) = "builtin" ]]; then
compopt -o nospace
fi
fi
__helm_debug "${FUNCNAME[0]}: final out is ${out[*]}"
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
}
__helm_list_releases()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local out filter
# Use ^ to map from the start of the release name
filter="^${words[c]}"
# Use eval in case helm_binary_name or __helm_override_flags contains a variable (e.g., $HOME/bin/h3)
if out=$(eval $(__helm_binary_name) list $(__helm_override_flags) -a -q -m 1000 -f ${filter} 2>/dev/null); then
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_list_repos()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local out
# Use eval in case helm_binary_name contains a variable (e.g., $HOME/bin/h3)
if out=$(__helm_get_repos); then
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_list_plugins()
{
__helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local out
# Use eval in case helm_binary_name contains a variable (e.g., $HOME/bin/h3)
if out=$(eval $(__helm_binary_name) plugin list 2>/dev/null | tail +2 | cut -f1); then
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__helm_list_charts_after_name() {
__helm_debug "${FUNCNAME[0]}: last_command is $last_command"
if [[ ${#nouns[@]} -eq 1 ]]; then
__helm_list_charts 1
fi
}
__helm_list_releases_then_charts() {
__helm_debug "${FUNCNAME[0]}: last_command is $last_command"
if [[ ${#nouns[@]} -eq 0 ]]; then
__helm_list_releases
elif [[ ${#nouns[@]} -eq 1 ]]; then
__helm_list_charts 1
fi
}
__helm_custom_func()
{
__helm_debug "${FUNCNAME[0]}: last_command is $last_command"
case ${last_command} in
helm_pull)
__helm_list_charts 0
return
;;
helm_show_*)
__helm_list_charts 1
return
;;
helm_install | helm_template)
__helm_list_charts_after_name
return
;;
helm_upgrade)
__helm_list_releases_then_charts
return
;;
helm_uninstall | helm_history | helm_status | helm_test |\
helm_rollback | helm_get_*)
__helm_list_releases
return
;;
helm_repo_remove)
__helm_list_repos
return
;;
helm_plugin_uninstall | helm_plugin_update)
__helm_list_plugins
return
;;
*)
;;
esac
}
`
)
@ -301,7 +49,8 @@ var (
// Mapping of global flags that can have dynamic completion and the
// completion function to be used.
bashCompletionFlags = map[string]string{
"namespace": "__helm_get_namespaces",
// Cannot convert the kube-context flag to Go completion yet because
// an incomplete kube-context will make actionConfig.Init() fail at the very start
"kube-context": "__helm_get_contexts",
}
)
@ -352,12 +101,34 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
Long: globalUsage,
SilenceUsage: true,
Args: require.NoArgs,
BashCompletionFunction: fmt.Sprintf(bashCompletionFunc, strings.Join(output.Formats(), " ")),
BashCompletionFunction: fmt.Sprintf("%s%s", contextCompFunc, completion.GetBashCustomFunction()),
}
flags := cmd.PersistentFlags()
settings.AddFlags(flags)
flag := flags.Lookup("namespace")
// Setup shell completion for the namespace flag
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if client, err := actionConfig.KubernetesClientSet(); err == nil {
// Choose a long enough timeout that the user notices somethings is not working
// but short enough that the user is not made to wait very long
to := int64(3)
completion.CompDebugln(fmt.Sprintf("About to call kube client for namespaces with timeout of: %d", to))
nsNames := []string{}
if namespaces, err := client.CoreV1().Namespaces().List(metav1.ListOptions{TimeoutSeconds: &to}); err == nil {
for _, ns := range namespaces.Items {
if strings.HasPrefix(ns.Name, toComplete) {
nsNames = append(nsNames, ns.Name)
}
}
return nsNames, completion.BashCompDirectiveNoFileComp
}
}
return nil, completion.BashCompDirectiveDefault
})
// We can safely ignore any errors that flags.Parse encounters since
// those errors will be caught later during the call to cmd.Execution.
// This call is required to gather configuration information prior to
@ -397,6 +168,9 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
// Hidden documentation generator command: 'helm docs'
newDocsCmd(out),
// Setup the special hidden __complete command to allow for dynamic auto-completion
completion.NewCompleteCmd(settings, out),
)
// Add annotation to flags for which we can generate completion choices
@ -418,7 +192,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
registry.ClientOptWriter(out),
)
if err != nil {
// TODO: dont panic here, refactor newRootCmd to return error
// TODO: don't panic here, refactor newRootCmd to return error
panic(err)
}
actionConfig.RegistryClient = registryClient

@ -31,28 +31,28 @@ func TestRootCmd(t *testing.T) {
tests := []struct {
name, args, cachePath, configPath, dataPath string
envars map[string]string
envvars map[string]string
}{
{
name: "defaults",
args: "home",
args: "env",
},
{
name: "with $XDG_CACHE_HOME set",
args: "home",
envars: map[string]string{xdg.CacheHomeEnvVar: "/bar"},
args: "env",
envvars: map[string]string{xdg.CacheHomeEnvVar: "/bar"},
cachePath: "/bar/helm",
},
{
name: "with $XDG_CONFIG_HOME set",
args: "home",
envars: map[string]string{xdg.ConfigHomeEnvVar: "/bar"},
args: "env",
envvars: map[string]string{xdg.ConfigHomeEnvVar: "/bar"},
configPath: "/bar/helm",
},
{
name: "with $XDG_DATA_HOME set",
args: "home",
envars: map[string]string{xdg.DataHomeEnvVar: "/bar"},
args: "env",
envvars: map[string]string{xdg.DataHomeEnvVar: "/bar"},
dataPath: "/bar/helm",
},
}
@ -61,7 +61,7 @@ func TestRootCmd(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
defer ensure.HelmHome(t)()
for k, v := range tt.envars {
for k, v := range tt.envvars {
os.Setenv(k, v)
}

@ -49,5 +49,8 @@ func TestSearchHubCmd(t *testing.T) {
t.Log(out)
t.Log(expected)
}
}
func TestSearchHubOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "search hub")
}

@ -17,8 +17,11 @@ limitations under the License.
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"path/filepath"
"strings"
@ -28,6 +31,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/search"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/helmpath"
"helm.sh/helm/v3/pkg/repo"
@ -246,3 +250,137 @@ func (r *repoSearchWriter) encodeByFormat(out io.Writer, format output.Format) e
// WriteJSON and WriteYAML, we shouldn't get invalid types
return nil
}
// Provides the list of charts that are part of the specified repo, and that starts with 'prefix'.
func compListChartsOfRepo(repoName string, prefix string) []string {
var charts []string
path := filepath.Join(settings.RepositoryCache, helmpath.CacheChartsFile(repoName))
content, err := ioutil.ReadFile(path)
if err == nil {
scanner := bufio.NewScanner(bytes.NewReader(content))
for scanner.Scan() {
fullName := fmt.Sprintf("%s/%s", repoName, scanner.Text())
if strings.HasPrefix(fullName, prefix) {
charts = append(charts, fullName)
}
}
return charts
}
if isNotExist(err) {
// If there is no cached charts file, fallback to the full index file.
// This is much slower but can happen after the caching feature is first
// installed but before the user does a 'helm repo update' to generate the
// first cached charts file.
path = filepath.Join(settings.RepositoryCache, helmpath.CacheIndexFile(repoName))
if indexFile, err := repo.LoadIndexFile(path); err == nil {
for name := range indexFile.Entries {
fullName := fmt.Sprintf("%s/%s", repoName, name)
if strings.HasPrefix(fullName, prefix) {
charts = append(charts, fullName)
}
}
return charts
}
}
return []string{}
}
// Provide dynamic auto-completion for commands that operate on charts (e.g., helm show)
// When true, the includeFiles argument indicates that completion should include local files (e.g., local charts)
func compListCharts(toComplete string, includeFiles bool) ([]string, completion.BashCompDirective) {
completion.CompDebugln(fmt.Sprintf("compListCharts with toComplete %s", toComplete))
noSpace := false
noFile := false
var completions []string
// First check completions for repos
repos := compListRepos("")
for _, repo := range repos {
repoWithSlash := fmt.Sprintf("%s/", repo)
if strings.HasPrefix(toComplete, repoWithSlash) {
// Must complete with charts within the specified repo
completions = append(completions, compListChartsOfRepo(repo, toComplete)...)
noSpace = false
break
} else if strings.HasPrefix(repo, toComplete) {
// Must complete the repo name
completions = append(completions, repoWithSlash)
noSpace = true
}
}
completion.CompDebugln(fmt.Sprintf("Completions after repos: %v", completions))
// Now handle completions for url prefixes
for _, url := range []string{"https://", "http://", "file://"} {
if strings.HasPrefix(toComplete, url) {
// The user already put in the full url prefix; we don't have
// anything to add, but make sure the shell does not default
// to file completion since we could be returning an empty array.
noFile = true
noSpace = true
} else if strings.HasPrefix(url, toComplete) {
// We are completing a url prefix
completions = append(completions, url)
noSpace = true
}
}
completion.CompDebugln(fmt.Sprintf("Completions after urls: %v", completions))
// Finally, provide file completion if we need to.
// We only do this if:
// 1- There are other completions found (if there are no completions,
// the shell will do file completion itself)
// 2- If there is some input from the user (or else we will end up
// listing the entire content of the current directory which will
// be too many choices for the user to find the real repos)
if includeFiles && len(completions) > 0 && len(toComplete) > 0 {
if files, err := ioutil.ReadDir("."); err == nil {
for _, file := range files {
if strings.HasPrefix(file.Name(), toComplete) {
// We are completing a file prefix
completions = append(completions, file.Name())
}
}
}
}
completion.CompDebugln(fmt.Sprintf("Completions after files: %v", completions))
// If the user didn't provide any input to completion,
// we provide a hint that a path can also be used
if includeFiles && len(toComplete) == 0 {
completions = append(completions, "./", "/")
}
completion.CompDebugln(fmt.Sprintf("Completions after checking empty input: %v", completions))
directive := completion.BashCompDirectiveDefault
if noFile {
directive = directive | completion.BashCompDirectiveNoFileComp
}
if noSpace {
directive = directive | completion.BashCompDirectiveNoSpace
// The completion.BashCompDirective flags do not work for zsh right now.
// We handle it ourselves instead.
completions = compEnforceNoSpace(completions)
}
return completions, directive
}
// This function prevents the shell from adding a space after
// a completion by adding a second, fake completion.
// It is only needed for zsh, but we cannot tell which shell
// is being used here, so we do the fake completion all the time;
// there are no real downsides to doing this for bash as well.
func compEnforceNoSpace(completions []string) []string {
// To prevent the shell from adding space after the completion,
// we trick it by pretending there is a second, longer match.
// We only do this if there is a single choice for completion.
if len(completions) == 1 {
completions = append(completions, completions[0]+".")
completion.CompDebugln(fmt.Sprintf("compEnforceNoSpace: completions now are %v", completions))
}
return completions
}

@ -83,3 +83,7 @@ func TestSearchRepositoriesCmd(t *testing.T) {
}
runTestCmd(t, tests)
}
func TestSearchRepoOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "search repo")
}

@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
)
@ -61,6 +62,14 @@ func newShowCmd(out io.Writer) *cobra.Command {
Args: require.NoArgs,
}
// Function providing dynamic auto-completion
validArgsFunc := func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListCharts(toComplete, true)
}
all := &cobra.Command{
Use: "all [CHART]",
Short: "shows all information of the chart",
@ -145,6 +154,9 @@ func newShowCmd(out io.Writer) *cobra.Command {
for _, subCmd := range cmds {
addChartPathOptionsFlags(subCmd.Flags(), &client.ChartPathOptions)
showCommand.AddCommand(subCmd)
// Register the completion function for each subcommand
completion.RegisterValidArgsFunc(subCmd, validArgsFunc)
}
return showCommand

@ -25,18 +25,20 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/release"
)
// NOTE: Keep the list of statuses up-to-date with pkg/release/status.go.
var statusHelp = `
This command shows the status of a named release.
The status consists of:
- last deployment time
- k8s namespace in which the release lives
- state of the release (can be: unknown, deployed, deleted, superseded, failed or deleting)
- state of the release (can be: unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade or pending-rollback)
- list of resources that this release consists of, sorted by kind
- details on last test suite run, if applicable
- additional notes provided by the chart
@ -64,8 +66,25 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) != 0 {
return nil, completion.BashCompDirectiveNoFileComp
}
return compListReleases(toComplete, cfg)
})
f := cmd.PersistentFlags()
f.IntVar(&client.Version, "revision", 0, "if set, display the status of the named release with revision")
flag := f.Lookup("revision")
completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
if len(args) == 1 {
return compListRevisions(cfg, args[0])
}
return nil, completion.BashCompDirectiveNoFileComp
})
bindOutputFlag(cmd, &outfmt)
return cmd

@ -108,3 +108,66 @@ func mustParseTime(t string) helmtime.Time {
res, _ := helmtime.Parse(time.RFC3339, t)
return res
}
func TestStatusCompletion(t *testing.T) {
releasesMockWithStatus := func(info *release.Info, hooks ...*release.Hook) []*release.Release {
info.LastDeployed = helmtime.Unix(1452902400, 0).UTC()
return []*release.Release{{
Name: "athos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "porthos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "aramis",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "dartagnan",
Namespace: "gascony",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}}
}
tests := []cmdTestCase{{
name: "completion for status",
cmd: "__complete status a",
golden: "output/status-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for status with too many arguments",
cmd: "__complete status dartagnan ''",
golden: "output/status-wrong-args-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for status with too many arguments",
cmd: "__complete status --debug a",
golden: "output/status-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}}
runTestCmd(t, tests)
}
func TestStatusRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "status")
}
func TestStatusOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "status")
}

@ -29,6 +29,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/internal/completion"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli/values"
@ -44,6 +45,7 @@ faked locally. Additionally, none of the server-side testing of chart validity
func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
var validate bool
var includeCrds bool
client := action.NewInstall(cfg)
valueOpts := &values.Options{}
var extraAPIs []string
@ -60,14 +62,15 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client.Replace = true // Skip the name check
client.ClientOnly = !validate
client.APIVersions = chartutil.VersionSet(extraAPIs)
client.IncludeCRDs = includeCrds
rel, err := runInstall(args, client, valueOpts, out)
if err != nil {
return err
}
var manifests bytes.Buffer
fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest))
if !client.DisableHooks {
for _, m := range rel.Hooks {
fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest)
@ -103,10 +106,10 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
if missing {
return fmt.Errorf("could not find template %s in chart", f)
}
}
for _, m := range manifestsToRender {
fmt.Fprintf(out, "---\n%s\n", m)
}
}
} else {
fmt.Fprintf(out, "%s", manifests.String())
}
@ -115,12 +118,21 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
},
}
// Function providing dynamic auto-completion
completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
return compInstall(args, toComplete, client)
})
f := cmd.Flags()
addInstallFlags(f, client, valueOpts)
f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates")
f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout")
f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install")
f.BoolVar(&includeCrds, "include-crds", false, "include CRDs in the templated output")
f.BoolVar(&client.IsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall")
f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions")
f.BoolVar(&client.UseReleaseName, "release-name", false, "use release name in the output-dir path.")
bindPostRenderFlag(cmd, &client.PostRenderer)
return cmd
}

@ -79,6 +79,29 @@ func TestTemplateCmd(t *testing.T) {
cmd: fmt.Sprintf("template --api-versions helm.k8s.io/test '%s'", chartPath),
golden: "output/template-with-api-version.txt",
},
{
name: "template with CRDs",
cmd: fmt.Sprintf("template '%s' --include-crds", chartPath),
golden: "output/template-with-crds.txt",
},
{
name: "template with show-only one",
cmd: fmt.Sprintf("template '%s' --show-only templates/service.yaml", chartPath),
golden: "output/template-show-only-one.txt",
},
{
name: "template with show-only multiple",
cmd: fmt.Sprintf("template '%s' --show-only templates/service.yaml --show-only charts/subcharta/templates/service.yaml", chartPath),
golden: "output/template-show-only-multiple.txt",
},
{
name: "sorted output of manifests (order of filenames, then order of objects within each YAML file)",
cmd: fmt.Sprintf("template '%s'", "testdata/testcharts/object-order"),
golden: "output/object-order.txt",
// Helm previously used random file order. Repeat the test so we
// don't accidentally get the expected result.
repeat: 10,
},
}
runTestCmd(t, tests)
}

@ -0,0 +1,7 @@
WARNING: This chart is deprecated
NAME: aeneas
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

@ -0,0 +1,16 @@
==> Linting testdata/testcharts/chart-with-bad-subcharts
[INFO] Chart.yaml: icon is recommended
[WARNING] templates/: directory not found
==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart
[ERROR] Chart.yaml: name is required
[ERROR] Chart.yaml: apiVersion is required. The value must be either "v1" or "v2"
[ERROR] Chart.yaml: version is required
[INFO] Chart.yaml: icon is recommended
[WARNING] templates/: directory not found
==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart
[INFO] Chart.yaml: icon is recommended
[WARNING] templates/: directory not found
Error: 3 chart(s) linted, 1 chart(s) failed

@ -0,0 +1,5 @@
==> Linting testdata/testcharts/chart-with-bad-subcharts
[INFO] Chart.yaml: icon is recommended
[WARNING] templates/: directory not found
1 chart(s) linted, 0 chart(s) failed

@ -0,0 +1,2 @@
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
starlord milano 2 2016-01-16 00:00:01 +0000 UTC deployed chickadee-1.0.0 0.0.1

@ -0,0 +1,191 @@
---
# Source: object-order/templates/01-a.yml
# 1
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: first
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/01-a.yml
# 2
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: second
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/01-a.yml
# 3
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: third
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 5
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fifth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 7
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: seventh
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 8
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: eighth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 9
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ninth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 10
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 11
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: eleventh
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 12
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: twelfth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 13
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: thirteenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 14
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fourteenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/02-b.yml
# 15 (11th object within 02-b.yml, in order to test `SplitManifests` which assigns `manifest-10`
# to this object which should then come *after* `manifest-9`)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fifteenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# Source: object-order/templates/01-a.yml
# 4 (Deployment should come after all NetworkPolicy manifests, since 'helm template' outputs in install order)
apiVersion: apps/v1
kind: Deployment
metadata:
name: fourth
spec:
selector:
matchLabels:
pod: fourth
replicas: 1
template:
metadata:
labels:
pod: fourth
spec:
containers:
- name: hello-world
image: gcr.io/google-samples/node-hello:1.0
---
# Source: object-order/templates/02-b.yml
# 6 (implementation detail: currently, 'helm template' outputs hook manifests last; and yes, NetworkPolicy won't make a reasonable hook, this is just a dummy unit test manifest)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
annotations:
"helm.sh/hook": pre-install
name: sixth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress

@ -0,0 +1,4 @@
table
json
yaml
:0

@ -1,2 +0,0 @@
NAME CHART VERSION APP VERSION DESCRIPTION
testing/mariadb 0.3.0 Chart for MariaDB

@ -0,0 +1,3 @@
aramis
athos
:4

@ -1,9 +0,0 @@
NAME: flummoxed-chickadee
LAST DEPLOYED: 2016-01-16 00:00:00 +0000 UTC
NAMESPACE: default
STATUS: deployed
RESOURCES:
resource A
resource B

@ -1,10 +0,0 @@
info:
deleted: "0001-01-01T00:00:00Z"
first_deployed: "0001-01-01T00:00:00Z"
last_deployed: "2016-01-16T00:00:00Z"
resources: |
resource A
resource B
status: deployed
name: flummoxed-chickadee
namespace: default

@ -0,0 +1,39 @@
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
helm.sh/chart: "subchart1-0.1.0"
app.kubernetes.io/instance: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "16"
kube-version/version: "v1.16.0"
kube-api-version/test: v1
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app.kubernetes.io/name: subchart1
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
helm.sh/chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app.kubernetes.io/name: subcharta

@ -0,0 +1,22 @@
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
helm.sh/chart: "subchart1-0.1.0"
app.kubernetes.io/instance: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "16"
kube-version/version: "v1.16.0"
kube-api-version/test: v1
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app.kubernetes.io/name: subchart1

@ -0,0 +1,72 @@
---
# Source: crds/crdA.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: testCRDs
spec:
group: testCRDGroups
names:
kind: TestCRD
listKind: TestCRDList
plural: TestCRDs
shortNames:
- tc
singular: authconfig
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
helm.sh/chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app.kubernetes.io/name: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
helm.sh/chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app.kubernetes.io/name: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
helm.sh/chart: "subchart1-0.1.0"
app.kubernetes.io/instance: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "16"
kube-version/version: "v1.16.0"
kube-api-version/test: v1
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app.kubernetes.io/name: subchart1

@ -1 +1 @@
version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""}

@ -1 +1 @@
version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""}

@ -1 +1 @@
v3.0+unreleased
v3.1

@ -1 +1 @@
Version: v3.0+unreleased
Version: v3.1

@ -1 +1 @@
version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""}

@ -14,7 +14,7 @@ metadata:
app.kubernetes.io/version: {{ .Chart.AppVersion }}
# This makes it easy to audit chart usage.
helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}"
values: {{.Values.test.Name}}
values: {{.Values.Name}}
spec:
# This shows how to use a simple value. This will look for a passed-in value
# called restartPolicy. If it is not found, it will use the default value.

@ -0,0 +1,4 @@
apiVersion: v1
description: Chart with bad subcharts
name: chart-with-bad-subcharts
version: 0.0.1

@ -0,0 +1,4 @@
apiVersion: v1
description: Good subchart
name: good-subchart
version: 0.0.1

@ -0,0 +1,5 @@
dependencies:
- name: good-subchart
version: 0.0.1
- name: bad-subchart
version: 0.0.1

@ -0,0 +1,8 @@
apiVersion: v1
description: Deprecated testing chart
home: https://helm.sh/helm
name: deprecated
sources:
- https://github.com/helm/helm
version: 0.1.0
deprecated: true

@ -0,0 +1,3 @@
#Deprecated
This space intentionally left blank.

@ -0,0 +1,22 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

@ -0,0 +1,5 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: issue-7233
version: 0.1.0

@ -0,0 +1,6 @@
dependencies:
- name: alpine
repository: file://../alpine
version: 0.1.0
digest: sha256:7b380b1a826e7be1eecb089f66209d6d3df54be4bf879d4a8e6f8a9e871710e5
generated: "2020-01-31T11:30:21.911547651Z"

@ -0,0 +1,4 @@
dependencies:
- name: alpine
version: 0.1.0
repository: file://../alpine

@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favoriteDrink }}

@ -0,0 +1 @@
favoriteDrink: coffee

@ -0,0 +1,5 @@
apiVersion: v2
name: object-order
description: Test ordering of manifests in output
type: application
version: 0.1.0

@ -0,0 +1,57 @@
# 1
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: first
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 2
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: second
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 3
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: third
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 4 (Deployment should come after all NetworkPolicy manifests, since 'helm template' outputs in install order)
apiVersion: apps/v1
kind: Deployment
metadata:
name: fourth
spec:
selector:
matchLabels:
pod: fourth
replicas: 1
template:
metadata:
labels:
pod: fourth
spec:
containers:
- name: hello-world
image: gcr.io/google-samples/node-hello:1.0

@ -0,0 +1,143 @@
# 5
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fifth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 6 (implementation detail: currently, 'helm template' outputs hook manifests last; and yes, NetworkPolicy won't make a reasonable hook, this is just a dummy unit test manifest)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
annotations:
"helm.sh/hook": pre-install
name: sixth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 7
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: seventh
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 8
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: eighth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 9
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ninth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 10
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 11
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: eleventh
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 12
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: twelfth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 13
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: thirteenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 14
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fourteenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress
---
# 15 (11th object within 02-b.yml, in order to test `SplitManifests` which assigns `manifest-10`
# to this object which should then come *after* `manifest-9`)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fifteenth
spec:
podSelector: {}
policyTypes:
- Egress
- Ingress

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

Loading…
Cancel
Save