Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(GH-33): Support rule loading from config file #41

Merged
merged 2 commits into from
Dec 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .travelgrunt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
rules:
- prefix: vendor/
exclude: true
- prefix: fixtures/
exclude: true
- name: '^.*\.go$'
2 changes: 1 addition & 1 deletion cmd/travelgrunt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func main() {
log.Fatalf("failed to load travelgrunt config: %s", err.Error())
}

entries, paths, err := directory.Collect(rootPath, cfg.IncludeFn)
entries, paths, err := directory.Collect(rootPath, cfg)

if err != nil {
log.Fatalf("failed to collect Terragrunt project directories: %s", err.Error())
Expand Down
3 changes: 2 additions & 1 deletion fixtures/config/travelgrunt.yml.dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mode: dockerfile
rules:
- mode: dockerfile
2 changes: 2 additions & 0 deletions fixtures/config/travelgrunt.yml.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rules:
- mode: groovy
3 changes: 2 additions & 1 deletion fixtures/config/travelgrunt.yml.illegal
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mode: bogus
rules:
- mode: bogus
1 change: 0 additions & 1 deletion fixtures/config/travelgrunt.yml.jenkins

This file was deleted.

2 changes: 2 additions & 0 deletions fixtures/config/travelgrunt.yml.jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rules:
- mode: jenkinsfile
3 changes: 2 additions & 1 deletion fixtures/config/travelgrunt.yml.terraform
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mode: terraform
rules:
- mode: terraform
4 changes: 3 additions & 1 deletion fixtures/config/travelgrunt.yml.terraform_or_terragrunt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
mode: terraform_or_terragrunt
rules:
- mode: terraform
- mode: terragrunt
3 changes: 2 additions & 1 deletion fixtures/config/travelgrunt.yml.terragrunt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mode: terragrunt
rules:
- mode: terragrunt
57 changes: 25 additions & 32 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package config

import (
"fmt"
"os"

"gopkg.in/yaml.v3"
Expand All @@ -11,14 +10,21 @@ import (

var configFile = ".travelgrunt.yml"

// Config contains travelgrunt repo-level configuration
// Config is a travelgrunt repo-level configuration (a sequentially evaluated list of rules)
type Config struct {
Mode string `yaml:"mode"`
IncludeFn func(os.DirEntry) bool
Rules []Rule `yaml:"rules"`

IsDefault bool
}

// DefaultConfig returns default travelgrunt repo-level configuration
func DefaultConfig() Config {
return Config{
Rules: []Rule{{IncludeFn: include.IsTerragrunt}},
IsDefault: true,
}
}

// NewConfig creates new travelgrunt repo-level configuration
func NewConfig(path string) (cfg Config, err error) {
var data []byte
Expand All @@ -34,39 +40,26 @@ func NewConfig(path string) (cfg Config, err error) {
return cfg, err
}

cfg.IncludeFn, err = GetIncludeFn(cfg.Mode)
for idx := range cfg.Rules {
cfg.Rules[idx].IncludeFn, err = getIncludeFn(cfg.Rules[idx].Mode)

return cfg, err
}
if err != nil {
cfg.Rules = nil

// DefaultConfig returns default travelgrunt repo-level configuration
func DefaultConfig() Config {
return Config{
Mode: "terragrunt",
IncludeFn: include.IsTerragrunt,
IsDefault: true,
return cfg, err
}
}
}

// GetIncludeFn gets an "include" func for the given mode (if mode is unknown, it returns a nil func and a non-nil error)
func GetIncludeFn(mode string) (fn func(os.DirEntry) bool, err error) {
err = nil
return cfg, nil
}

switch mode {
case "terragrunt":
fn = include.IsTerragrunt
case "terraform":
fn = include.IsTerraform
case "terraform_or_terragrunt":
fn = include.IsTerraformOrTerragrunt
case "dockerfile":
fn = include.IsDockerfile
case "jenkins":
fn = include.IsJenkins
default:
fn = nil
err = fmt.Errorf("illegal mode: %s", mode)
// Include is a global "decider" function that includes/excludes the path given according to rules
func (cfg Config) Include(d os.DirEntry, rel string) bool {
for idx := range cfg.Rules {
if cfg.Rules[idx].Include(d, rel) {
return !cfg.Rules[idx].Exclude
}
}

return fn, err
return false
}
35 changes: 17 additions & 18 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,63 @@ const (
fixturePath = "../../fixtures/config"
)

func TestCornerCases(t *testing.T) {
func TestNewConfigCornerCases(t *testing.T) {
assert := assert.New(t)

testCases := map[string]struct {
cfg Config
success bool
}{
"travelgrunt.yml.invalid": {cfg: Config{Mode: "", IncludeFn: nil, IsDefault: false}, success: false},
"travelgrunt.yml.illegal": {cfg: Config{Mode: "bogus", IncludeFn: nil, IsDefault: false}, success: false},
"travelgrunt.yml.nonexistent": {cfg: Config{Mode: "terragrunt", IncludeFn: include.IsTerragrunt, IsDefault: true}, success: true},
"travelgrunt.yml.invalid": {cfg: Config{Rules: nil, IsDefault: false}, success: false},
"travelgrunt.yml.illegal": {cfg: Config{Rules: nil, IsDefault: false}, success: false},
"travelgrunt.yml.nonexistent": {cfg: Config{Rules: []Rule{{Mode: "terragrunt", IncludeFn: include.IsTerragrunt}}, IsDefault: true}, success: true},
}

for cfgFile, expected := range testCases {
configFile = cfgFile

cfg, err := NewConfig(fixturePath)

assert.Equal(expected.cfg.Mode, cfg.Mode)
assert.Equal(expected.cfg.IsDefault, cfg.IsDefault)

if expected.success {
assert.NotNil(cfg.IncludeFn)
assert.NotNil(cfg.Rules)
assert.Nil(err)
} else {
assert.Nil(cfg.IncludeFn)
assert.Nil(cfg.Rules)
assert.NotNil(err)
}
}
}

func getNormalConfig(mode string) Config {
includeFn, _ := GetIncludeFn(mode)
fn, _ := getIncludeFn(mode)

return Config{Mode: mode, IncludeFn: includeFn, IsDefault: false}
return Config{Rules: []Rule{{Mode: mode, IncludeFn: fn}}, IsDefault: false}
}

func TestNormalFlow(t *testing.T) {
func TestNewConfigNormalFlow(t *testing.T) {
assert := assert.New(t)

testCases := map[string]Config{
"travelgrunt.yml.terragrunt": getNormalConfig("terragrunt"),
"travelgrunt.yml.terraform": getNormalConfig("terraform"),
"travelgrunt.yml.terraform_or_terragrunt": getNormalConfig("terraform_or_terragrunt"),
"travelgrunt.yml.dockerfile": getNormalConfig("dockerfile"),
"travelgrunt.yml.jenkins": getNormalConfig("jenkins"),
"travelgrunt.yml.terragrunt": getNormalConfig("terragrunt"),
"travelgrunt.yml.terraform": getNormalConfig("terraform"),
"travelgrunt.yml.dockerfile": getNormalConfig("dockerfile"),
"travelgrunt.yml.jenkinsfile": getNormalConfig("jenkinsfile"),
"travelgrunt.yml.groovy": getNormalConfig("groovy"),
}

for cfgFile, expected := range testCases {
configFile = cfgFile

cfg, err := NewConfig(fixturePath)

assert.Equal(expected.Mode, cfg.Mode)
assert.NotNil(expected.Rules, cfg.Rules)
assert.Equal(expected.IsDefault, false)

assert.Equalf(
runtime.FuncForPC(reflect.ValueOf(expected.IncludeFn).Pointer()).Name(),
runtime.FuncForPC(reflect.ValueOf(cfg.IncludeFn).Pointer()).Name(),
runtime.FuncForPC(reflect.ValueOf(expected.Rules[0].IncludeFn).Pointer()).Name(),
runtime.FuncForPC(reflect.ValueOf(cfg.Rules[0].IncludeFn).Pointer()).Name(),
"got unexpected include function while loading config file: %s", configFile,
)

Expand Down
3 changes: 2 additions & 1 deletion pkg/config/include/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"os"
)

func fileOrSymlink(d os.DirEntry) bool {
// FileOrSymlink tells us if dir entry in question is a regular file or a symlink
func FileOrSymlink(d os.DirEntry) bool {
return d.Type().IsRegular() || d.Type() == os.ModeSymlink
}
2 changes: 1 addition & 1 deletion pkg/config/include/dockerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import (

// IsDockerfile tells us if we operate on Dockerfile(s) or Dockerfile template(s)
func IsDockerfile(d os.DirEntry) bool {
return fileOrSymlink(d) && strings.Contains(strings.ToLower(d.Name()), "dockerfile")
return FileOrSymlink(d) && strings.Contains(strings.ToLower(d.Name()), "dockerfile")
}
2 changes: 1 addition & 1 deletion pkg/config/include/groovy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import (

// IsGroovy tells us we operate on Groovy file(s)
func IsGroovy(d os.DirEntry) bool {
return fileOrSymlink(d) && strings.HasSuffix(d.Name(), ".groovy")
return FileOrSymlink(d) && strings.HasSuffix(d.Name(), ".groovy")
}
10 changes: 0 additions & 10 deletions pkg/config/include/jenkins.go

This file was deleted.

9 changes: 0 additions & 9 deletions pkg/config/include/jenkins_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/config/include/jenkinsfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import (

// IsJenkinsfile tells us we operate on Jenkinsfile(s)
func IsJenkinsfile(d os.DirEntry) bool {
return fileOrSymlink(d) && strings.Contains(strings.ToLower(d.Name()), "jenkinsfile")
return FileOrSymlink(d) && strings.Contains(strings.ToLower(d.Name()), "jenkinsfile")
}
2 changes: 1 addition & 1 deletion pkg/config/include/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import (

// IsTerraform tells us if we operate on Terraform file(s)
func IsTerraform(d os.DirEntry) bool {
return fileOrSymlink(d) && strings.HasSuffix(d.Name(), ".tf")
return FileOrSymlink(d) && strings.HasSuffix(d.Name(), ".tf")
}
10 changes: 0 additions & 10 deletions pkg/config/include/terraform_or_terragrunt.go

This file was deleted.

9 changes: 0 additions & 9 deletions pkg/config/include/terraform_or_terragrunt_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/config/include/terragrunt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import (

// IsTerragrunt tells us if we operate on Terragrunt config file
func IsTerragrunt(d os.DirEntry) bool {
return fileOrSymlink(d) && d.Name() == "terragrunt.hcl"
return FileOrSymlink(d) && d.Name() == "terragrunt.hcl"
}
32 changes: 32 additions & 0 deletions pkg/config/include_fn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package config

import (
"fmt"
"os"

"github.com/ivanilves/travelgrunt/pkg/config/include"
)

func getIncludeFn(mode string) (fn func(os.DirEntry) bool, err error) {
err = nil

switch mode {
case "":
fn = nil
case "terragrunt":
fn = include.IsTerragrunt
case "terraform":
fn = include.IsTerraform
case "dockerfile":
fn = include.IsDockerfile
case "jenkinsfile":
fn = include.IsJenkinsfile
case "groovy":
fn = include.IsGroovy
default:
fn = nil
err = fmt.Errorf("illegal mode: %s", mode)
}

return fn, err
}
Loading