Skip to content

Commit

Permalink
Allow ignoring empty kinds or names. (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickdappollonio authored Aug 18, 2023
1 parent d6baa62 commit 7919256
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 2 deletions.
2 changes: 2 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ func root() *cobra.Command {
rootCommand.Flags().BoolVar(&opts.SortByKind, "sort-by-kind", false, "if enabled, resources are sorted by Kind, a la Helm, before saving them to disk")
rootCommand.Flags().BoolVar(&opts.OutputToStdout, "stdout", false, "if enabled, no resource is written to disk and all resources are printed to stdout instead")
rootCommand.Flags().StringVarP(&configFile, "config", "c", "", "path to the config file")
rootCommand.Flags().BoolVar(&opts.AllowEmptyKinds, "allow-empty-kinds", false, "if enabled, resources with empty kinds don't produce an error when filtering")
rootCommand.Flags().BoolVar(&opts.AllowEmptyNames, "allow-empty-names", false, "if enabled, resources with empty names don't produce an error when filtering")

_ = rootCommand.Flags().MarkHidden("debug")
return rootCommand
Expand Down
4 changes: 2 additions & 2 deletions slice/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ func (s *Split) parseYAMLManifest(contents []byte) (yamlFile, error) {
s.log.Printf("Kubernetes metadata found -> %#v", k8smeta)

// Check if we have a Kubernetes kind and we're requesting inclusion or exclusion
if k8smeta.Kind == "" && (hasIncluded || hasExcluded) {
if k8smeta.Kind == "" && !s.opts.AllowEmptyKinds && (hasIncluded || hasExcluded) {
return yamlFile{}, fmt.Errorf("unable to find Kubernetes \"kind\" field in file number %d", s.fileCount)
}

// Check if we have a Kubernetes name and we're requesting inclusion or exclusion
if k8smeta.Name == "" && (hasIncluded || hasExcluded) {
if k8smeta.Name == "" && !s.opts.AllowEmptyNames && (hasIncluded || hasExcluded) {
return yamlFile{}, fmt.Errorf("unable to find Kubernetes \"metadata.name\" field in file number %d", s.fileCount)
}

Expand Down
115 changes: 115 additions & 0 deletions slice/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,118 @@ kind: Foo
})
}
}

func TestSplit_parseYamlManifestAllowingEmpties(t *testing.T) {
tests := []struct {
name string
contents []byte
skipEmptyName bool
skipEmptyKind bool
includeKind string
includeName string
want yamlFile
wantErr bool
}{
{
name: "include name and kind",
contents: []byte(`---
apiVersion: v1
kind: Foo
metadata:
name: bar
`),
want: yamlFile{
filename: "foo-bar.yaml",
meta: kubeObjectMeta{APIVersion: "v1", Kind: "Foo", Name: "bar"},
},
includeKind: "Foo",
skipEmptyName: false,
skipEmptyKind: false,
},
{
name: "allow empty kind",
contents: []byte(`---
apiVersion: v1
kind: ""
metadata:
name: bar
`),
want: yamlFile{
filename: "-bar.yaml",
meta: kubeObjectMeta{APIVersion: "v1", Kind: "", Name: "bar"},
},
includeName: "bar",
skipEmptyName: false,
skipEmptyKind: true,
},
{
name: "dont allow empty kind",
contents: []byte(`---
apiVersion: v1
metadata:
name: bar
`),
wantErr: true,
includeName: "bar",
skipEmptyName: false,
skipEmptyKind: false,
},
{
name: "allow empty name",
contents: []byte(`---
apiVersion: v1
kind: Foo
metadata:
name: ""
`),
want: yamlFile{
filename: "foo-.yaml",
meta: kubeObjectMeta{APIVersion: "v1", Kind: "Foo", Name: ""},
},
includeKind: "Foo",
skipEmptyName: true,
skipEmptyKind: false,
},
{
name: "dont allow empty name",
contents: []byte(`---
apiVersion: v1
kind: Foo
`),
wantErr: true,
includeKind: "Foo",
skipEmptyName: false,
skipEmptyKind: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

s := &Split{
log: nolog,
template: template.Must(template.New(DefaultTemplateName).Funcs(local.Functions).Parse(DefaultTemplateName)),
}

if len(tt.includeKind) > 0 {
s.opts.IncludedKinds = []string{tt.includeKind}
}

if len(tt.includeName) > 0 {
s.opts.IncludedNames = []string{tt.includeName}
}

s.opts.AllowEmptyKinds = tt.skipEmptyKind
s.opts.AllowEmptyNames = tt.skipEmptyName

if err := s.validateFilters(); err != nil {
t.Fatalf("not expecting error validating filters, got: %s", err)
}

got, err := s.parseYAMLManifest(tt.contents)
requireErrorIf(t, tt.wantErr, err)
t.Logf("got: %#v", got)
require.Equal(t, tt.want, got)
})
}
}
3 changes: 3 additions & 0 deletions slice/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,7 @@ type Options struct {
StrictKubernetes bool // if true, any YAMLs that don't contain at least an "apiVersion", "kind" and "metadata.name" will be excluded

SortByKind bool // if true, it will sort the resources by kind

AllowEmptyNames bool
AllowEmptyKinds bool
}
16 changes: 16 additions & 0 deletions slice/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ func (s *Split) init() error {
}

func (s *Split) validateFilters() error {
if len(s.opts.IncludedKinds) > 0 && s.opts.AllowEmptyKinds {
return fmt.Errorf("cannot specify both included kinds and allow empty kinds")
}

if len(s.opts.ExcludedKinds) > 0 && s.opts.AllowEmptyKinds {
return fmt.Errorf("cannot specify both excluded kinds and allow empty kinds")
}

if len(s.opts.IncludedNames) > 0 && s.opts.AllowEmptyNames {
return fmt.Errorf("cannot specify both included names and allow empty names")
}

if len(s.opts.ExcludedNames) > 0 && s.opts.AllowEmptyNames {
return fmt.Errorf("cannot specify both excluded names and allow empty names")
}

if len(s.opts.IncludedKinds) > 0 && len(s.opts.ExcludedKinds) > 0 {
return fmt.Errorf("cannot specify both included and excluded kinds")
}
Expand Down
62 changes: 62 additions & 0 deletions slice/validate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package slice

import (
"testing"
)

func TestSplit_validateFilters(t *testing.T) {
tests := []struct {
name string
opts Options
wantErr bool
}{
{
name: "prevent using allow skipping kind while using included kinds",
opts: Options{
AllowEmptyKinds: true,
IncludedKinds: []string{"foo"},
},
wantErr: true,
},
{
name: "prevent using allow skipping kind while using excluded kinds",
opts: Options{
AllowEmptyKinds: true,
ExcludedKinds: []string{"foo"},
},
wantErr: true,
},
{
name: "prevent using allow skipping name while using included names",
opts: Options{
AllowEmptyNames: true,
IncludedNames: []string{"foo"},
},
wantErr: true,
},
{
name: "prevent using allow skipping name while using excluded names",
opts: Options{
AllowEmptyNames: true,
ExcludedNames: []string{"foo"},
},
wantErr: true,
},
{
name: "cannot specify included and excluded kinds",
opts: Options{
IncludedKinds: []string{"foo"},
ExcludedKinds: []string{"bar"},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Split{opts: tt.opts}
if err := s.validateFilters(); (err != nil) != tt.wantErr {
t.Errorf("Split.validateFilters() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

0 comments on commit 7919256

Please sign in to comment.