Skip to content

Commit

Permalink
[feature] TravisCI now allows per component configuration + allows to…
Browse files Browse the repository at this point in the history
… set a specific make command to run (#305)

[feature] TravisCI now allows per component configuration + allows to set a specific make command to run### Summary
- Mostly lifted from the Atlantis implementation

### Test Plan
- unittest
- run in existing repo
  • Loading branch information
Eduardo Lopez authored and czimergebot committed Jun 24, 2019
1 parent 81bef6d commit eb7367a
Show file tree
Hide file tree
Showing 13 changed files with 332 additions and 116 deletions.
18 changes: 10 additions & 8 deletions apply/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"testing"

"github.com/chanzuckerberg/fogg/config"
"github.com/chanzuckerberg/fogg/config/v1"
v1 "github.com/chanzuckerberg/fogg/config/v1"
"github.com/chanzuckerberg/fogg/templates"
"github.com/chanzuckerberg/fogg/util"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -236,13 +236,15 @@ func TestApplySmokeTest(t *testing.T) {
"infra_s3_bucket": "buck",
"project": "proj",
"terraform_version": "0.100.0",
"owner": "[email protected]"
},
"travis_ci": {
"enabled": true,
"aws_iam_role_name": "travis",
"id_account_name": "id",
"test_buckets": 7
"owner": "[email protected]",
"tools": {
"travis_ci": {
"enabled": true,
"aws_iam_role_name": "travis",
"id_account_name": "id",
"test_buckets": 7
}
}
},
"accounts": {
"foo": {
Expand Down
8 changes: 4 additions & 4 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func Test_detectVersion(t *testing.T) {
}
}

func intptr(i int64) *int64 {
func intptr(i int) *int {
return &i
}

Expand Down Expand Up @@ -111,9 +111,9 @@ func TestUpgradeConfigVersion(t *testing.T) {
Enabled: boolptr(true),
},
TravisCI: &v1.TravisCI{
Enabled: true,
AWSIAMRoleName: "travis-role",
TestBuckets: 13,
Enabled: boolptr(true),
AWSIAMRoleName: util.StrPtr("travis-role"),
TestBuckets: intptr(13),
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions config/v1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ type Module struct {
}

type TravisCI struct {
Enabled bool `json:"enabled,omitempty"`
AWSIAMRoleName string `json:"aws_iam_role_name"`
TestBuckets int `json:"test_buckets"`
Enabled *bool `json:"enabled,omitempty"`
AWSIAMRoleName *string `json:"aws_iam_role_name,omitempty"`
TestBuckets *int `json:"test_buckets,omitempty"`
Command *string `json:"command,omitempty"`
}

type Config struct {
Expand Down
13 changes: 11 additions & 2 deletions config/v2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ func (c *Config) Generate(r *rand.Rand, size int) reflect.Value {
return &str
}

randBoolPtr := func(r *rand.Rand, s int) *bool {
b := r.Float32() > 0.5
return &b
}
randIntPtr := func(r *rand.Rand, s int) *int {
i := r.Intn(s)
return &i
}

randStringMap := func(r *rand.Rand, s int) map[string]string {
m := map[string]string{}

Expand Down Expand Up @@ -226,8 +235,8 @@ func (c *Config) Generate(r *rand.Rand, size int) reflect.Value {
c.Tools = &Tools{}
if r.Float32() < 0.5 {
c.Tools.TravisCI = &v1.TravisCI{
Enabled: r.Float32() < 0.5,
TestBuckets: r.Intn(size),
Enabled: randBoolPtr(r, s),
TestBuckets: randIntPtr(r, s),
}
}
if r.Float32() < 0.5 {
Expand Down
36 changes: 36 additions & 0 deletions config/v2/resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,28 @@ func ResolveAtlantis(commons ...Common) *Atlantis {
}
}

func ResolveTravis(commons ...Common) *v1.TravisCI {
enabled := false
testCommand := "check"
for _, c := range commons {
if c.Tools != nil && c.Tools.TravisCI != nil && c.Tools.TravisCI.Enabled != nil {
enabled = *c.Tools.TravisCI.Enabled
}

if c.Tools != nil && c.Tools.TravisCI != nil && c.Tools.TravisCI.Command != nil {
testCommand = *c.Tools.TravisCI.Command
}
}

roleName := lastNonNil(TravisRoleNameGetter, commons...)

return &v1.TravisCI{
Enabled: &enabled,
AWSIAMRoleName: roleName,
Command: &testCommand,
}
}

func OwnerGetter(comm Common) *string {
return comm.Owner
}
Expand Down Expand Up @@ -367,3 +389,17 @@ func AtlantisRoleNameGetter(comm Common) *string {
}
return comm.Tools.Atlantis.RoleName
}

func TravisRoleNameGetter(comm Common) *string {
if comm.Tools == nil || comm.Tools.TravisCI == nil {
return nil
}
return comm.Tools.TravisCI.AWSIAMRoleName
}

func TravisTestCommandGetter(comm Common) *string {
if comm.Tools == nil || comm.Tools.TravisCI == nil {
return nil
}
return comm.Tools.TravisCI.Command
}
33 changes: 23 additions & 10 deletions config/v2/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import (
validator "gopkg.in/go-playground/validator.v9"
)

var validTravisCommands = map[string]struct{}{
"check": struct{}{},
"lint": struct{}{},
}

// Validate validates the config
func (c *Config) Validate() ([]string, error) {
if c == nil {
Expand Down Expand Up @@ -49,12 +54,10 @@ func (c *Config) Validate() ([]string, error) {
errs = multierror.Append(errs, c.ValidateOktaProviders())
errs = multierror.Append(errs, c.validateModules())
errs = multierror.Append(errs, c.ValidateAtlantis())
errs = multierror.Append(errs, c.ValidateTravis())

// refactor to make it easier to manage these
w, e := c.ValidateToolsTravis()
warnings = append(warnings, w...)
errs = multierror.Append(errs, e)
w, e = c.ValidateToolsTfLint()
w, e := c.ValidateToolsTfLint()
warnings = append(warnings, w...)
errs = multierror.Append(errs, e)

Expand Down Expand Up @@ -200,17 +203,27 @@ func (c *Config) ValidateBlessProviders() error {
return errs
}

func (c *Config) ValidateToolsTravis() ([]string, error) {
var warns []string
func (c *Config) ValidateTravis() error {
var errs *multierror.Error
c.WalkComponents(func(component string, comms ...Common) {
c := comms[len(comms)-1]
if c.Tools != nil && c.Tools.TravisCI != nil {
warns = append(warns, fmt.Sprintf("per-component travisci config is not implemented, ignoring config in %s", component))
t := ResolveTravis(comms...)
if t.Enabled == nil || *t.Enabled == false {
return // nothing to do
}

if t.AWSIAMRoleName == nil || *t.AWSIAMRoleName == "" {
errs = multierror.Append(errs, fmt.Errorf("if travis is enabled, aws_role_name must be set"))
}

if t.Command != nil {
_, ok := validTravisCommands[*t.Command]
if !ok {
errs = multierror.Append(errs, fmt.Errorf("unrecognized travisci command %s (%s)", *t.Command, component))
}
}
})

return warns, errs
return errs
}

func (c *Config) ValidateToolsTfLint() ([]string, error) {
Expand Down
23 changes: 23 additions & 0 deletions config/v2/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,26 @@ func TestConfig_ValidateAWSProviders(t *testing.T) {
})
}
}

func TestConfig_ValidateTravis(t *testing.T) {
tests := []struct {
fileName string
wantErr bool
}{
{"v2_invalid_travis_command", true},
}
for _, tt := range tests {
t.Run(tt.fileName, func(t *testing.T) {
r := require.New(t)

b, e := util.TestFile(tt.fileName)
r.NoError(e)
c, e := ReadConfig(b)
r.NoError(e)

if err := c.ValidateTravis(); (err != nil) != tt.wantErr {
t.Errorf("Config.ValidateTravis() error = %v, wantErr %v (err != nil) %v", err, tt.wantErr, (err != nil))
}
})
}
}
20 changes: 19 additions & 1 deletion plan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type ComponentCommon struct {
Project string
Providers Providers `yaml:"providers"`
TfLint TfLint
TravisCI TravisComponent
}

type AtlantisComponent struct {
Expand All @@ -47,6 +48,14 @@ type AtlantisComponent struct {
RolePath string `yaml:"role_path"`
}

type TravisComponent struct {
Enabled bool
AWSProfileName string
AWSRoleName string
AWSAccountID string
Command string
}

type Providers struct {
AWS *AWSProvider `yaml:"aws"`
Snowflake *SnowflakeProvider `yaml:"snowflake"`
Expand Down Expand Up @@ -153,8 +162,8 @@ func Eval(c *v2.Config) (*Plan, error) {
}

p.Modules = p.buildModules(c)
p.TravisCI = p.buildTravisCI(c, v)
p.Atlantis = p.buildAtlantis()
p.TravisCI = p.buildTravisCI(c, v)

return p, nil
}
Expand Down Expand Up @@ -323,7 +332,15 @@ func resolveComponentCommon(commons ...v2.Common) ComponentCommon {
if atlantisPlan.Enabled {
atlantisPlan.RoleName = *atlantisConfig.RoleName
atlantisPlan.RolePath = *atlantisConfig.RolePath
}

travisConfig := v2.ResolveTravis(commons...)
travisPlan := TravisComponent{
Enabled: *travisConfig.Enabled,
}
if travisPlan.Enabled {
travisPlan.AWSRoleName = *travisConfig.AWSIAMRoleName
travisPlan.Command = *travisConfig.Command
}

return ComponentCommon{
Expand All @@ -346,6 +363,7 @@ func resolveComponentCommon(commons ...v2.Common) ComponentCommon {
Owner: v2.ResolveRequiredString(v2.OwnerGetter, commons...),
Project: v2.ResolveRequiredString(v2.ProjectGetter, commons...),
Common: Common{TerraformVersion: v2.ResolveRequiredString(v2.TerraformVersionGetter, commons...)},
TravisCI: travisPlan,
}
}

Expand Down
Loading

0 comments on commit eb7367a

Please sign in to comment.