diff --git a/ct/cmd/root.go b/ct/cmd/root.go index 16b40485..3afb2621 100644 --- a/ct/cmd/root.go +++ b/ct/cmd/root.go @@ -80,6 +80,7 @@ func addCommonFlags(flags *pflag.FlagSet) { flags.Bool("github-groups", false, heredoc.Doc(` Change the delimiters for github to create collapsible groups for command output`)) + flags.Bool("use-helmignore", false, "Use .helmignore when identifying changed charts") } func addCommonLintAndInstallFlags(flags *pflag.FlagSet) { diff --git a/doc/ct_install.md b/doc/ct_install.md index 355a14c3..fe1e72d3 100644 --- a/doc/ct_install.md +++ b/doc/ct_install.md @@ -77,6 +77,7 @@ ct install [flags] --target-branch string The name of the target branch used to identify changed charts (default "main") --upgrade Whether to test an in-place upgrade of each chart from its previous revision if the current version should not introduce a breaking change according to the SemVer spec + --use-helmignore Use .helmignore when identifying changed charts ``` ### SEE ALSO diff --git a/doc/ct_lint-and-install.md b/doc/ct_lint-and-install.md index 765448fc..215a70fe 100644 --- a/doc/ct_lint-and-install.md +++ b/doc/ct_lint-and-install.md @@ -72,6 +72,7 @@ ct lint-and-install [flags] --target-branch string The name of the target branch used to identify changed charts (default "main") --upgrade Whether to test an in-place upgrade of each chart from its previous revision if the current version should not introduce a breaking change according to the SemVer spec + --use-helmignore Use .helmignore when identifying changed charts --validate-chart-schema Enable schema validation of 'Chart.yaml' using Yamale (default true) --validate-maintainers Enable validation of maintainer account names in chart.yml. Works for GitHub, GitLab, and Bitbucket (default true) diff --git a/doc/ct_lint.md b/doc/ct_lint.md index 5fb4ef62..2b6e57b9 100644 --- a/doc/ct_lint.md +++ b/doc/ct_lint.md @@ -70,6 +70,7 @@ ct lint [flags] --remote string The name of the Git remote used to identify changed charts (default "origin") --since string The Git reference used to identify changed charts (default "HEAD") --target-branch string The name of the target branch used to identify changed charts (default "main") + --use-helmignore Use .helmignore when identifying changed charts --validate-chart-schema Enable schema validation of 'Chart.yaml' using Yamale (default true) --validate-maintainers Enable validation of maintainer account names in chart.yml. Works for GitHub, GitLab, and Bitbucket (default true) @@ -79,4 +80,3 @@ ct lint [flags] ### SEE ALSO * [ct](ct.md) - The Helm chart testing tool - diff --git a/doc/ct_list-changed.md b/doc/ct_list-changed.md index 5080a62f..d757a711 100644 --- a/doc/ct_list-changed.md +++ b/doc/ct_list-changed.md @@ -28,9 +28,9 @@ ct list-changed [flags] --remote string The name of the Git remote used to identify changed charts (default "origin") --since string The Git reference used to identify changed charts (default "HEAD") --target-branch string The name of the target branch used to identify changed charts (default "main") + --use-helmignore Use .helmignore when identifying changed charts ``` ### SEE ALSO * [ct](ct.md) - The Helm chart testing tool - diff --git a/go.mod b/go.mod index a88fd0a6..56d01d5e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/helm/chart-testing/v3 -go 1.20 +go 1.21 + +toolchain go1.21.5 require ( github.com/MakeNowJust/heredoc v1.0.0 @@ -14,6 +16,7 @@ require ( github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.8.4 gopkg.in/yaml.v2 v2.4.0 + helm.sh/helm/v3 v3.12.0-dev.1.0.20240111190511-1df81d01d942 ) require ( @@ -27,6 +30,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect diff --git a/go.sum b/go.sum index 19f35acb..56a133f1 100644 --- a/go.sum +++ b/go.sum @@ -9,10 +9,13 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -20,6 +23,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= @@ -30,13 +34,17 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -45,10 +53,13 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= @@ -99,3 +110,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.12.0-dev.1.0.20240111190511-1df81d01d942 h1:s7iYDJ2d1zSXLG4s1L6YkBQEXsUzmRoBSGd1cPDobvw= +helm.sh/helm/v3 v3.12.0-dev.1.0.20240111190511-1df81d01d942/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index 0f1e1f92..c7c60e25 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -25,6 +25,7 @@ import ( "github.com/helm/chart-testing/v3/pkg/config" "github.com/helm/chart-testing/v3/pkg/exec" + "github.com/helm/chart-testing/v3/pkg/ignore" "github.com/helm/chart-testing/v3/pkg/tool" "github.com/helm/chart-testing/v3/pkg/util" ) @@ -242,6 +243,7 @@ type Testing struct { directoryLister DirectoryLister utils Utils previousRevisionWorktree string + loadRules func(string) (*ignore.Rules, error) } // TestResults holds results and overall status @@ -272,6 +274,7 @@ func NewTesting(config config.Configuration, extraSetArgs string) (Testing, erro accountValidator: tool.AccountValidator{}, directoryLister: util.DirectoryLister{}, utils: util.Utils{}, + loadRules: ignore.LoadRules, } versionString, err := testing.helm.Version() @@ -746,7 +749,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) { return nil, fmt.Errorf("failed creating diff: %w", err) } - var changedChartDirs []string + changedChartFiles := map[string][]string{} for _, file := range allChangedChartFiles { pathElements := strings.SplitN(filepath.ToSlash(file), "/", 3) if len(pathElements) < 2 || util.StringSliceContains(cfg.ExcludedCharts, pathElements[1]) { @@ -763,15 +766,33 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) { continue } } - // Only add it if not already in the list - if !util.StringSliceContains(changedChartDirs, chartDir) { - changedChartDirs = append(changedChartDirs, chartDir) - } + changedChartFiles[chartDir] = append(changedChartFiles[chartDir], strings.TrimPrefix(file, chartDir+"/")) } else { fmt.Fprintf(os.Stderr, "Directory %q is not a valid chart directory. Skipping...\n", dir) } } + changedChartDirs := []string{} + if t.config.UseHelmignore { + for chartDir, changedChartFiles := range changedChartFiles { + rules, err := t.loadRules(chartDir) + if err != nil { + return nil, err + } + filteredChartFiles, err := ignore.FilterFiles(changedChartFiles, rules) + if err != nil { + return nil, err + } + if len(filteredChartFiles) > 0 { + changedChartDirs = append(changedChartDirs, chartDir) + } + } + } else { + for chartDir := range changedChartFiles { + changedChartDirs = append(changedChartDirs, chartDir) + } + } + return changedChartDirs, nil } diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index a45ff829..c6add777 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/helm/chart-testing/v3/pkg/config" + "github.com/helm/chart-testing/v3/pkg/ignore" "github.com/helm/chart-testing/v3/pkg/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -152,6 +153,26 @@ func newTestingMock(cfg config.Configuration) Testing { accountValidator: fakeAccountValidator{}, linter: fakeMockLinter, helm: new(fakeHelm), + loadRules: func(dir string) (*ignore.Rules, error) { + rules := ignore.Empty() + if dir == "test_charts/foo" { + var err error + rules, err = ignore.Parse(strings.NewReader("Chart.yaml\n")) + if err != nil { + return nil, err + } + rules.AddDefaults() + } + if dir == "test_chart_at_multi_level/foo/baz" { + var err error + rules, err = ignore.Parse(strings.NewReader("Chart.yaml\n")) + if err != nil { + return nil, err + } + rules.AddDefaults() + } + return rules, nil + }, } } @@ -165,6 +186,19 @@ func TestComputeChangedChartDirectories(t *testing.T) { assert.Nil(t, err) } +func TestComputeChangedChartDirectoriesWithHelmignore(t *testing.T) { + cfg := config.Configuration{ + ExcludedCharts: []string{"excluded"}, + ChartDirs: []string{"test_charts", "."}, + UseHelmignore: true, + } + ct := newTestingMock(cfg) + actual, err := ct.ComputeChangedChartDirectories() + expected := []string{"test_charts/bar", "test_chart_at_root"} + assert.Nil(t, err) + assert.ElementsMatch(t, expected, actual) +} + func TestComputeChangedChartDirectoriesWithMultiLevelChart(t *testing.T) { cfg := config.Configuration{ ExcludedCharts: []string{"excluded"}, @@ -180,6 +214,19 @@ func TestComputeChangedChartDirectoriesWithMultiLevelChart(t *testing.T) { assert.Nil(t, err) } +func TestComputeChangedChartDirectoriesWithMultiLevelChartWithHelmIgnore(t *testing.T) { + cfg := config.Configuration{ + ExcludedCharts: []string{"excluded"}, + ChartDirs: []string{"test_chart_at_multi_level/foo"}, + UseHelmignore: true, + } + ct := newTestingMock(cfg) + actual, err := ct.ComputeChangedChartDirectories() + expected := []string{"test_chart_at_multi_level/foo/bar"} + assert.Nil(t, err) + assert.ElementsMatch(t, expected, actual) +} + func TestReadAllChartDirectories(t *testing.T) { actual, err := ct.ReadAllChartDirectories() expected := []string{ diff --git a/pkg/config/config.go b/pkg/config/config.go index c6b82874..989c467b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -73,6 +73,7 @@ type Configuration struct { KubectlTimeout time.Duration `mapstructure:"kubectl-timeout"` PrintLogs bool `mapstructure:"print-logs"` GithubGroups bool `mapstructure:"github-groups"` + UseHelmignore bool `mapstructure:"use-helmignore"` } func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*Configuration, error) { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 80b33f0e..f07d912e 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -61,6 +61,7 @@ func loadAndAssertConfigFromFile(t *testing.T, configFile string) { require.Equal(t, true, cfg.ExcludeDeprecated) require.Equal(t, 120*time.Second, cfg.KubectlTimeout) require.Equal(t, true, cfg.SkipCleanUp) + require.Equal(t, true, cfg.UseHelmignore) } func Test_findConfigFile(t *testing.T) { diff --git a/pkg/config/test_config.json b/pkg/config/test_config.json index 4dc445a8..73cd4574 100644 --- a/pkg/config/test_config.json +++ b/pkg/config/test_config.json @@ -32,5 +32,6 @@ "release-label": "release", "exclude-deprecated": true, "kubectl-timeout": "120s", - "skip-clean-up": true + "skip-clean-up": true, + "use-helmignore": true } diff --git a/pkg/config/test_config.yaml b/pkg/config/test_config.yaml index 6fe391de..0d1c7c02 100644 --- a/pkg/config/test_config.yaml +++ b/pkg/config/test_config.yaml @@ -28,3 +28,4 @@ release-label: release exclude-deprecated: true kubectl-timeout: 120s skip-clean-up: true +use-helmignore: true diff --git a/pkg/ignore/ignore.go b/pkg/ignore/ignore.go new file mode 100644 index 00000000..93525783 --- /dev/null +++ b/pkg/ignore/ignore.go @@ -0,0 +1,83 @@ +/* +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 ignore + +import ( + "io/fs" + "os" + "path/filepath" + "testing/fstest" + + "helm.sh/helm/v3/pkg/ignore" +) + +func LoadRules(dir string) (*ignore.Rules, error) { + rules, err := ignore.ParseFile(filepath.Join(dir, ignore.HelmIgnore)) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if rules == nil { + rules = ignore.Empty() + } + rules.AddDefaults() + return rules, nil +} + +func FilterFiles(files []string, rules *ignore.Rules) ([]string, error) { + fsys := fstest.MapFS{} + for _, file := range files { + fsys[file] = &fstest.MapFile{} + } + + filteredFiles := []string{} + + err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + fi, err := d.Info() + if err != nil { + return err + } + + // Normalize to / since it will also work on Windows + path = filepath.ToSlash(path) + + if fi.IsDir() { + // Directory-based ignore rules should involve skipping the entire + // contents of that directory. + if rules.Ignore(path, fi) { + return filepath.SkipDir + } + return nil + } + + // If a .helmignore file matches, skip this file. + if rules.Ignore(path, fi) { + return nil + } + + filteredFiles = append(filteredFiles, path) + return nil + }) + if err != nil { + return nil, err + } + + return filteredFiles, nil +} diff --git a/pkg/ignore/ignore_test.go b/pkg/ignore/ignore_test.go new file mode 100644 index 00000000..4fe9c385 --- /dev/null +++ b/pkg/ignore/ignore_test.go @@ -0,0 +1,19 @@ +package ignore + +import ( + "strings" + "testing" + + "github.com/helm/chart-testing/v3/pkg/ignore" + "github.com/stretchr/testify/assert" +) + +func TestFilter(t *testing.T) { + rules, err := ignore.Parse(strings.NewReader("/bar/\nREADME.md\n")) + assert.Nil(t, err) + files := []string{"Chart.yaml", "bar/xxx", "template/svc.yaml", "baz/bar/biz.txt", "README.md"} + actual, err := FilterFiles(files, rules) + assert.Nil(t, err) + expected := []string{"Chart.yaml", "baz/bar/biz.txt", "template/svc.yaml"} + assert.ElementsMatch(t, expected, actual) +}