fix: testcase and add new case for `helm template`

Signed-off-by: wujunwei <wjw3323@live.com>
pull/11551/head
wujunwei 3 years ago
parent 07dae737a0
commit da5af20be7

@ -92,25 +92,13 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
}
fileWritten := make(map[string]bool)
// deal hooks
if !client.DisableHooks {
for _, m := range rel.Hooks {
if matchFilePatterns(m.Path, showFiles) || (skipTests && isTestHook(m)) {
continue
}
err = writeManifest(outputDir, m.Path, m.Manifest, fileWritten, out)
if err != nil {
return err
}
}
}
// deal crds
if includeCrds && !client.SkipCRDs && rel.Chart != nil {
for _, crd := range rel.Chart.CRDObjects() {
if !matchFilePatterns(crd.Name, showFiles) {
if len(showFiles) > 0 && !matchFilePatterns(crd.Name, showFiles) {
continue
}
err = writeManifest(outputDir, crd.Name, string(crd.File.Data), fileWritten, out)
err := writeManifest(outputDir, filepath.ToSlash(crd.Filename), string(crd.File.Data), fileWritten, true, out)
if err != nil {
return err
}
@ -124,7 +112,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
// with globs or directory names.
splitManifests := releaseutil.SplitManifests(manifests.String())
manifestsKeys := make([]string, 0, len(splitManifests))
manifestNameRegex := regexp.MustCompile("# Source: [^/]+/(.+)")
manifestNameRegex := regexp.MustCompile("# Source: ([^/]+/)(.+)")
for k := range splitManifests {
manifestsKeys = append(manifestsKeys, k)
}
@ -132,14 +120,27 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
for _, manifestKey := range manifestsKeys {
manifest := splitManifests[manifestKey]
submatch := manifestNameRegex.FindStringSubmatch(manifest)
var manifestName string
if len(submatch) > 1 {
manifestName = submatch[1]
}
if matchFilePatterns(manifestName, showFiles) {
// remove text like # Source: XXX/XXX.yaml
manifest = manifestNameRegex.ReplaceAllString(manifest, "")
//err = writeManifest(outputDir, , manifest, fileWritten, out) todo
var manifestName, manifestPath string
if len(submatch) > 2 {
manifestName = submatch[2]
manifestPath = submatch[1] + submatch[2]
}
if len(showFiles) > 0 && !matchFilePatterns(manifestName, showFiles) {
continue
}
err := writeManifest(outputDir, manifestPath, manifest, fileWritten, false, out)
if err != nil {
return err
}
}
// deal hooks
if !client.DisableHooks {
for _, m := range rel.Hooks {
if (skipTests && isTestHook(m)) || (len(showFiles) > 0 && !matchFilePatterns(m.Name, showFiles)) {
continue
}
err := writeManifest(outputDir, m.Path, m.Manifest, fileWritten, true, out)
if err != nil {
return err
}
@ -175,8 +176,8 @@ func isTestHook(h *release.Hook) bool {
}
// writeToFile write manifests into output dir.
func writeToFile(outputDir string, name string, data string, append bool) error {
outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator))
func writeToFile(outputDir string, name string, data string, append, withHeader bool) error {
outfileName := filepath.Join(outputDir, name)
err := ensureDirectoryForFile(outfileName)
if err != nil {
@ -190,7 +191,7 @@ func writeToFile(outputDir string, name string, data string, append bool) error
defer f.Close()
_, err = f.WriteString(fmt.Sprintf("---\n# Source: %s\n%s\n", name, data))
err = writeStream(name, data, withHeader, f)
if err != nil {
return err
@ -218,9 +219,6 @@ func ensureDirectoryForFile(file string) error {
}
func matchFilePatterns(target string, sf []string) bool {
if len(sf) == 0 {
return true
}
for _, pattern := range sf {
pattern = filepath.ToSlash(pattern)
matched, _ := filepath.Match(pattern, target)
@ -231,11 +229,12 @@ func matchFilePatterns(target string, sf []string) bool {
return false
}
func writeManifest(outputDir, path, manifest string, fileWritten map[string]bool, outStream io.Writer) error {
// writeManifest write manifest to stdout or file stream. use withHeader to control if write file header `# Source: XXXXX.yaml` or not.
func writeManifest(outputDir, path, manifest string, fileWritten map[string]bool, withHeader bool, outStream io.Writer) error {
if outputDir == "" {
fmt.Fprintf(outStream, "---\n# Source: %s\n%s\n", path, manifest)
return writeStream(path, manifest, withHeader, outStream)
} else {
err := writeToFile(outputDir, path, manifest, fileWritten[path])
err := writeToFile(outputDir, path, manifest, fileWritten[path], withHeader)
if err != nil {
return err
}
@ -243,3 +242,22 @@ func writeManifest(outputDir, path, manifest string, fileWritten map[string]bool
}
return nil
}
func writeStream(path, manifest string, withHeader bool, outStream io.Writer) error {
//write yaml delimiter
_, err := fmt.Fprintf(outStream, "---\n")
if err != nil {
return err
}
//write file header
if withHeader {
_, err = fmt.Fprintf(outStream, "# Source: %s\n", path)
if err != nil {
return err
}
}
//write manifest content
_, err = fmt.Fprintf(outStream, "%s\n", manifest)
return err
}

@ -18,6 +18,8 @@ package main
import (
"fmt"
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"testing"
)
@ -165,6 +167,138 @@ func TestTemplateVersionCompletion(t *testing.T) {
runTestCmd(t, tests)
}
func TestTemplateOutputDir(t *testing.T) {
is := assert.New(t)
dir := t.TempDir()
releaseName := "madra"
_, out, err := executeActionCommand(fmt.Sprintf("template %s '%s' --output-dir=%s", releaseName, chartPath, dir))
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
}
var exitFileList = [][]string{
{dir, "subchart", "templates", "service.yaml"},
{dir, "subchart", "templates", "tests", "test-config.yaml"},
{dir, "subchart", "templates", "tests", "test-nothing.yaml"},
{dir, "subchart", "templates", "subdir", "role.yaml"},
{dir, "subchart", "templates", "subdir", "rolebinding.yaml"},
{dir, "subchart", "templates", "subdir", "serviceaccount.yaml"},
{dir, "subchart", "charts", "subcharta", "templates", "service.yaml"},
{dir, "subchart", "charts", "subchartb", "templates", "service.yaml"},
}
for _, s := range exitFileList {
_, err = os.Stat(filepath.Join(s...))
is.NoError(err)
}
notExistFileList := [][]string{
{dir, "hello", "templates", "empty"},
{dir, releaseName, "subchart", "templates", "service.yaml"},
{dir, releaseName, "subchart", "templates", "tests", "test-config.yaml"},
{dir, releaseName, "subchart", "templates", "tests", "test-nothing.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "role.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "rolebinding.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "serviceaccount.yaml"},
{dir, releaseName, "subchart", "charts", "subcharta", "templates", "service.yaml"},
{dir, releaseName, "subchart", "charts", "subchartb", "templates", "service.yaml"},
}
for _, f := range notExistFileList {
_, err = os.Stat(filepath.Join(f...))
is.True(os.IsNotExist(err))
}
}
func TestTemplateWithCRDsOutputDir(t *testing.T) {
is := assert.New(t)
dir := t.TempDir()
releaseName := "madra"
_, out, err := executeActionCommand(fmt.Sprintf("template %s '%s' --output-dir=%s --include-crds", releaseName, chartPath, dir))
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
}
var exitFileList = [][]string{
{dir, "subchart", "crds", "crdA.yaml"},
}
for _, s := range exitFileList {
_, err = os.Stat(filepath.Join(s...))
is.NoError(err)
}
notExistFileList := [][]string{
{dir, "hello", "templates", "empty"},
{dir, releaseName, "subchart", "templates", "service.yaml"},
{dir, releaseName, "subchart", "templates", "tests", "test-config.yaml"},
{dir, releaseName, "subchart", "templates", "tests", "test-nothing.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "role.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "rolebinding.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "serviceaccount.yaml"},
{dir, releaseName, "subchart", "charts", "subcharta", "templates", "service.yaml"},
{dir, releaseName, "subchart", "charts", "subchartb", "templates", "service.yaml"},
}
for _, f := range notExistFileList {
_, err = os.Stat(filepath.Join(f...))
is.True(os.IsNotExist(err))
}
}
func TestTemplateOutputDirWithReleaseName(t *testing.T) {
is := assert.New(t)
dir := t.TempDir()
releaseName := "madra"
_, out, err := executeActionCommand(fmt.Sprintf("template %s '%s' --output-dir=%s --release-name", releaseName, chartPath, dir))
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
}
var exitFileList = [][]string{
{dir, releaseName, "subchart", "templates", "service.yaml"},
{dir, releaseName, "subchart", "templates", "tests", "test-config.yaml"},
{dir, releaseName, "subchart", "templates", "tests", "test-nothing.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "role.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "rolebinding.yaml"},
{dir, releaseName, "subchart", "templates", "subdir", "serviceaccount.yaml"},
{dir, releaseName, "subchart", "charts", "subcharta", "templates", "service.yaml"},
{dir, releaseName, "subchart", "charts", "subchartb", "templates", "service.yaml"},
}
for _, s := range exitFileList {
_, err = os.Stat(filepath.Join(s...))
is.NoError(err)
}
notExistFileList := [][]string{
{dir, releaseName, "hello", "templates", "empty"},
{dir, "subchart", "templates", "service.yaml"},
{dir, "subchart", "templates", "tests", "test-config.yaml"},
{dir, "subchart", "templates", "tests", "test-nothing.yaml"},
{dir, "subchart", "templates", "subdir", "role.yaml"},
{dir, "subchart", "templates", "subdir", "rolebinding.yaml"},
{dir, "subchart", "templates", "subdir", "serviceaccount.yaml"},
{dir, "subchart", "charts", "subcharta", "templates", "service.yaml"},
{dir, "subchart", "charts", "subchartb", "templates", "service.yaml"},
}
for _, f := range notExistFileList {
_, err = os.Stat(filepath.Join(f...))
is.True(os.IsNotExist(err))
}
}
func TestTemplateOutputDirSkiptest(t *testing.T) {
is := assert.New(t)
dir := t.TempDir()
releaseName := "madra"
_, out, err := executeActionCommand(fmt.Sprintf("template %s '%s' --output-dir=%s --skip-tests", releaseName, chartPath, dir))
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
}
notExistFileList := [][]string{
{dir, "subchart", "templates", "tests", "test-config.yaml"},
{dir, "subchart", "templates", "tests", "test-nothing.yaml"},
}
for _, f := range notExistFileList {
_, err = os.Stat(filepath.Join(f...))
is.True(os.IsNotExist(err))
}
}
func TestTemplateFileCompletion(t *testing.T) {
checkFileCompletion(t, "template", false)
checkFileCompletion(t, "template --generate-name", true)

@ -1,38 +1,38 @@
---
# Source: subchart/templates/service.yaml
# Source: subchart/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart
name: subcharta
labels:
helm.sh/chart: "subchart-0.1.0"
app.kubernetes.io/instance: "release-name"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
helm.sh/chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
name: apache
selector:
app.kubernetes.io/name: subchart
app.kubernetes.io/name: subcharta
---
# Source: subchart/charts/subcharta/templates/service.yaml
# Source: subchart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
name: subchart
labels:
helm.sh/chart: "subcharta-0.1.0"
helm.sh/chart: "subchart-0.1.0"
app.kubernetes.io/instance: "release-name"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
name: nginx
selector:
app.kubernetes.io/name: subcharta
app.kubernetes.io/name: subchart

@ -1,5 +1,5 @@
---
# Source: crds/crdA.yaml
# Source: subchart/crds/crdA.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:

@ -59,8 +59,6 @@ import (
// since there can be filepath in front of it.
const notesFileSuffix = "NOTES.txt"
const defaultDirectoryPermission = 0755
// Install performs an installation operation.
type Install struct {
cfg *Configuration
@ -83,12 +81,14 @@ type Install struct {
GenerateName bool
NameTemplate string
Description string
// OutputDir is deprecated because of template-related code is removed from install action.
// Deprecated
OutputDir string
Atomic bool
SkipCRDs bool
SubNotes bool
DisableOpenAPIValidation bool
// IncludeCRDs is deprecated because of template-related code is removed from install action.
// Deprecated
IncludeCRDs bool
// KubeVersion allows specifying a custom kubernetes version to use and
@ -98,9 +98,10 @@ type Install struct {
APIVersions chartutil.VersionSet
// Used by helm template to render charts with .Release.IsUpgrade. Ignored if Dry-Run is false
IsUpgrade bool
// Used by helm template to add the release as part of OutputDir path
// Used by helm template to add the release as part of OutputDir path, UseReleaseName is deprecated because of template-related code is removed from install action.
// OutputDir/<ReleaseName>
UseReleaseName bool // Deprecated
//Deprecated
UseReleaseName bool
PostRenderer postrender.PostRenderer
// Lock to control raceconditions when the process receives a SIGTERM
Lock sync.Mutex
@ -216,7 +217,7 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
}
if i.ClientOnly {
// Add mock objects in here so it doesn't use Kube API server
// Add mock objects in here, so it doesn't use Kube API server
// NOTE(bacongobbler): used for `helm template`
i.cfg.Capabilities = chartutil.DefaultCapabilities.Copy()
if i.KubeVersion != nil {

@ -20,8 +20,6 @@ import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
@ -30,7 +28,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"helm.sh/helm/v3/internal/test"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
@ -546,74 +543,6 @@ func TestNameTemplate(t *testing.T) {
}
}
func TestInstallReleaseOutputDir(t *testing.T) {
is := assert.New(t)
instAction := installAction(t)
vals := map[string]interface{}{}
dir := t.TempDir()
instAction.OutputDir = dir
_, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
_, err = os.Stat(filepath.Join(dir, "hello/templates/goodbye"))
is.NoError(err)
_, err = os.Stat(filepath.Join(dir, "hello/templates/hello"))
is.NoError(err)
_, err = os.Stat(filepath.Join(dir, "hello/templates/with-partials"))
is.NoError(err)
_, err = os.Stat(filepath.Join(dir, "hello/templates/rbac"))
is.NoError(err)
test.AssertGoldenFile(t, filepath.Join(dir, "hello/templates/rbac"), "rbac.txt")
_, err = os.Stat(filepath.Join(dir, "hello/templates/empty"))
is.True(os.IsNotExist(err))
}
func TestInstallOutputDirWithReleaseName(t *testing.T) {
is := assert.New(t)
instAction := installAction(t)
vals := map[string]interface{}{}
dir := t.TempDir()
instAction.OutputDir = dir
instAction.UseReleaseName = true
instAction.ReleaseName = "madra"
newDir := filepath.Join(dir, instAction.ReleaseName)
_, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
_, err = os.Stat(filepath.Join(newDir, "hello/templates/goodbye"))
is.NoError(err)
_, err = os.Stat(filepath.Join(newDir, "hello/templates/hello"))
is.NoError(err)
_, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials"))
is.NoError(err)
_, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac"))
is.NoError(err)
test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt")
_, err = os.Stat(filepath.Join(newDir, "hello/templates/empty"))
is.True(os.IsNotExist(err))
}
func TestNameAndChart(t *testing.T) {
is := assert.New(t)
instAction := installAction(t)

Loading…
Cancel
Save