Skip to content

Commit 8b30fb5

Browse files
authored
Adds new zero-module conditions parameter (#308)
* Adds new zero-module conditions parameter - Currently only supports 'ignoreFile' condition * Add package documentation * Use RemoveAll to support recursively removing directories
1 parent ae7e2e2 commit 8b30fb5

File tree

9 files changed

+188
-17
lines changed

9 files changed

+188
-17
lines changed

internal/condition/condition.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// This module is invoked when we do template rendering during "zero create."
2+
//
3+
// Each module can have a "conditions" section in their zero-module.yml that
4+
// specifies a condition in the form:
5+
//
6+
// conditions:
7+
// - action: ignoreFile
8+
// matchField: <the name of a parameter in zero-module.yml>
9+
// whenValue: <value for the matchField that triggers this condition>
10+
// data:
11+
// - <arbitrary string>
12+
//
13+
// The structure for this is defined in:
14+
// internal/config/projectconfig/project_config.go.
15+
// The definition is in that file simply to avoid cyclic dependencies; but
16+
// The logic for each type of condition exists here.
17+
//
18+
// See: internal/generate/generate_modules.go
19+
// See: internal/config/projectconfig/project_config.go
20+
//
21+
package condition
22+
23+
import (
24+
"os"
25+
"path"
26+
27+
"github.com/commitdev/zero/internal/config/projectconfig"
28+
)
29+
30+
// Function dispatch for any kind of condition.
31+
func Perform(cond projectconfig.Condition, mod projectconfig.Module) {
32+
value, found := mod.Parameters[cond.MatchField]
33+
34+
// Exit if the condition isn't met.
35+
if !found || value != cond.WhenValue {
36+
return
37+
}
38+
39+
// Okay, the condition was met, let's execute it.
40+
switch cond.Action {
41+
case "ignoreFile":
42+
ignoreFile(cond.Data, mod)
43+
}
44+
}
45+
46+
// Excludes paths from template rendering.
47+
// This occurs after-the-fact. That is, we render all templates to disk, then
48+
// use 'paths' to determine which files and directories to remove from disk.
49+
//
50+
func ignoreFile(paths []string, mod projectconfig.Module) {
51+
for _, file := range paths {
52+
filepath := path.Join(mod.Files.Directory, file)
53+
os.RemoveAll(filepath)
54+
}
55+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package condition_test
2+
3+
import (
4+
"math/rand"
5+
"os"
6+
"testing"
7+
8+
"github.com/commitdev/zero/internal/condition"
9+
"github.com/commitdev/zero/internal/config/projectconfig"
10+
)
11+
12+
func testSetup(paramKey, paramValue string) (string, projectconfig.Module) {
13+
bytes := make([]byte, 15)
14+
_, _ = rand.Read(bytes)
15+
name := string(bytes[:])
16+
17+
_, _ = os.Create(name)
18+
19+
params := make(projectconfig.Parameters)
20+
params[paramKey] = paramValue
21+
22+
mod := projectconfig.Module{
23+
Parameters: params,
24+
Files: projectconfig.Files{
25+
Directory: ".",
26+
Source: ".",
27+
},
28+
}
29+
30+
return name, mod
31+
}
32+
33+
func TestPerformIgnoreFileConditionNotMet(t *testing.T) {
34+
field := "testField"
35+
value := "trigger"
36+
37+
filename, mod := testSetup(field, "other value")
38+
defer os.Remove(filename)
39+
40+
cond := projectconfig.Condition{
41+
Action: "ignoreFile",
42+
MatchField: field,
43+
WhenValue: value,
44+
Data: []string{filename},
45+
}
46+
condition.Perform(cond, mod)
47+
48+
_, err := os.Stat(filename)
49+
if err != nil && !os.IsExist(err) {
50+
t.Errorf("Expected %v not to be removed\n", filename)
51+
}
52+
}
53+
54+
func TestPerformIgnoreFileConditionMet(t *testing.T) {
55+
field := "testField"
56+
value := "trigger"
57+
58+
filename, mod := testSetup(field, value)
59+
defer os.Remove(filename)
60+
61+
cond := projectconfig.Condition{
62+
Action: "ignoreFile",
63+
MatchField: field,
64+
WhenValue: value,
65+
Data: []string{filename},
66+
}
67+
condition.Perform(cond, mod)
68+
69+
_, err := os.Stat(filename)
70+
if !os.IsNotExist(err) {
71+
t.Errorf("Expected %v to be removed\n", filename)
72+
}
73+
}

internal/config/moduleconfig/module_config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type ModuleConfig struct {
1414
TemplateConfig `yaml:"template"`
1515
RequiredCredentials []string `yaml:"requiredCredentials"`
1616
Parameters []Parameter
17+
Conditions []Condition `yaml:"conditions,omitempty"`
1718
}
1819

1920
type Parameter struct {
@@ -27,6 +28,13 @@ type Parameter struct {
2728
FieldValidation Validate `yaml:"fieldValidation,omitempty"`
2829
}
2930

31+
type Condition struct {
32+
Action string `yaml:"action"`
33+
MatchField string `yaml:"matchField"`
34+
WhenValue string `yaml:"whenValue"`
35+
Data []string `yaml:"data,omitempty"`
36+
}
37+
3038
type Validate struct {
3139
Type string `yaml:"type,omitempty"`
3240
Value string `yaml:"value,omitempty"`
@@ -50,5 +58,6 @@ func LoadModuleConfig(filePath string) (ModuleConfig, error) {
5058
if err != nil {
5159
return config, err
5260
}
61+
5362
return config, nil
5463
}

internal/config/projectconfig/project_config.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,18 @@ type Module struct {
2626
DependsOn []string `yaml:"dependsOn,omitempty"`
2727
Parameters Parameters `yaml:"parameters,omitempty"`
2828
Files Files
29+
Conditions []Condition `yaml:"conditions,omitempty"`
2930
}
3031

3132
type Parameters map[string]string
3233

34+
type Condition struct {
35+
Action string `yaml:"action"`
36+
MatchField string `yaml:"matchField"`
37+
WhenValue string `yaml:"whenValue"`
38+
Data []string `yaml:"data,omitempty"`
39+
}
40+
3341
type Files struct {
3442
Directory string `yaml:"dir,omitempty"`
3543
Repository string `yaml:"repo,omitempty"`
@@ -77,7 +85,7 @@ func (c *ZeroProjectConfig) GetDAG() dag.AcyclicGraph {
7785
return g
7886
}
7987

80-
func NewModule(parameters Parameters, directory string, repository string, source string, dependsOn []string) Module {
88+
func NewModule(parameters Parameters, directory string, repository string, source string, dependsOn []string, conditions []Condition) Module {
8189
return Module{
8290
Parameters: parameters,
8391
DependsOn: dependsOn,
@@ -86,5 +94,6 @@ func NewModule(parameters Parameters, directory string, repository string, sourc
8694
Repository: repository,
8795
Source: source,
8896
},
97+
Conditions: conditions,
8998
}
9099
}

internal/config/projectconfig/project_config_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ func TestLoadConfig(t *testing.T) {
4040
func eksGoReactSampleModules() projectconfig.Modules {
4141
parameters := projectconfig.Parameters{"a": "b"}
4242
return projectconfig.Modules{
43-
"aws-eks-stack": projectconfig.NewModule(parameters, "zero-aws-eks-stack", "github.com/something/repo1", "github.com/commitdev/zero-aws-eks-stack", []string{}),
44-
"deployable-backend": projectconfig.NewModule(parameters, "zero-deployable-backend", "github.com/something/repo2", "github.com/commitdev/zero-deployable-backend", []string{}),
45-
"deployable-react-frontend": projectconfig.NewModule(parameters, "zero-deployable-react-frontend", "github.com/something/repo3", "github.com/commitdev/zero-deployable-react-frontend", []string{}),
43+
"aws-eks-stack": projectconfig.NewModule(parameters, "zero-aws-eks-stack", "github.com/something/repo1", "github.com/commitdev/zero-aws-eks-stack", []string{}, []projectconfig.Condition{}),
44+
"deployable-backend": projectconfig.NewModule(parameters, "zero-deployable-backend", "github.com/something/repo2", "github.com/commitdev/zero-deployable-backend", []string{}, []projectconfig.Condition{}),
45+
"deployable-react-frontend": projectconfig.NewModule(parameters, "zero-deployable-react-frontend", "github.com/something/repo3", "github.com/commitdev/zero-deployable-react-frontend", []string{}, []projectconfig.Condition{}),
4646
}
4747
}
4848

internal/generate/generate_modules.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"sync"
1212
"text/template"
1313

14+
"github.com/commitdev/zero/internal/condition"
1415
"github.com/commitdev/zero/internal/config/projectconfig"
1516
"github.com/commitdev/zero/internal/constants"
1617
"github.com/commitdev/zero/internal/module"
@@ -47,19 +48,25 @@ func Generate(projectConfig projectconfig.ZeroProjectConfig, overwriteFiles bool
4748

4849
// Data that will be passed in to each template
4950
templateData := struct {
50-
Name string
51-
Params projectconfig.Parameters
52-
Files projectconfig.Files
51+
Name string
52+
Params projectconfig.Parameters
53+
Files projectconfig.Files
54+
Conditions []projectconfig.Condition
5355
}{
5456
projectConfig.Name,
5557
mod.Parameters,
5658
mod.Files,
59+
mod.Conditions,
5760
}
5861

5962
txtTypeFiles, binTypeFiles := sortFileType(moduleDir, outputDir, overwriteFiles)
6063

6164
executeTemplates(txtTypeFiles, templateData, delimiters)
6265
copyBinFiles(binTypeFiles)
66+
67+
for _, cond := range mod.Conditions {
68+
condition.Perform(cond, mod)
69+
}
6370
}
6471
return nil
6572
}

internal/generate/generate_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestGenerateModules(t *testing.T) {
2929
projectConfig := projectconfig.ZeroProjectConfig{
3030
Name: "foo",
3131
Modules: projectconfig.Modules{
32-
"mod1": projectconfig.NewModule(map[string]string{"test": "bar"}, tmpDir, "github.com/fake-org/repo-foo", baseTestFixturesDir, []string{}),
32+
"mod1": projectconfig.NewModule(map[string]string{"test": "bar"}, tmpDir, "github.com/fake-org/repo-foo", baseTestFixturesDir, []string{}, []projectconfig.Condition{}),
3333
},
3434
}
3535
generate.Generate(projectConfig, true)

internal/init/init.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func Init(outDir string, localModulePath string) *projectconfig.ZeroProjectConfi
5959
repoName := prompts[moduleName].GetParam(initParams)
6060
repoURL := fmt.Sprintf("%s/%s", initParams["GithubRootOrg"], repoName)
6161
projectModuleParams := make(projectconfig.Parameters)
62+
projectModuleConditions := []projectconfig.Condition{}
6263

6364
// Loop through all the prompted values and find the ones relevant to this module
6465
for parameterKey, parameterValue := range projectParameters {
@@ -67,9 +68,26 @@ func Init(outDir string, localModulePath string) *projectconfig.ZeroProjectConfi
6768
projectModuleParams[parameterKey] = parameterValue
6869
}
6970
}
71+
}
7072

73+
for _, condition := range module.Conditions {
74+
newCond := projectconfig.Condition{
75+
Action: condition.Action,
76+
MatchField: condition.MatchField,
77+
WhenValue: condition.WhenValue,
78+
Data: condition.Data,
79+
}
80+
projectModuleConditions = append(projectModuleConditions, newCond)
7181
}
72-
projectConfig.Modules[moduleName] = projectconfig.NewModule(projectModuleParams, repoName, repoURL, mappedSources[moduleName], module.DependsOn)
82+
83+
projectConfig.Modules[moduleName] = projectconfig.NewModule(
84+
projectModuleParams,
85+
repoName,
86+
repoURL,
87+
mappedSources[moduleName],
88+
module.DependsOn,
89+
projectModuleConditions,
90+
)
7391
}
7492

7593
// TODO: load ~/.zero/config.yml (or credentials)

internal/registry/registry.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ func GetRegistry(path string) Registry {
1212
{
1313
"EKS + Go + React + Gatsby",
1414
[]string{
15-
path+"/zero-aws-eks-stack",
16-
path+"/zero-deployable-landing-page",
17-
path+"/zero-deployable-backend",
18-
path+"/zero-deployable-react-frontend",
15+
path + "/zero-aws-eks-stack",
16+
path + "/zero-deployable-landing-page",
17+
path + "/zero-deployable-backend",
18+
path + "/zero-deployable-react-frontend",
1919
},
2020
},
2121
{
2222
"EKS + NodeJS + React + Gatsby",
2323
[]string{
24-
path+"/zero-aws-eks-stack",
25-
path+"/zero-deployable-landing-page",
26-
path+"/zero-deployable-node-backend",
27-
path+"/zero-deployable-react-frontend",
24+
path + "/zero-aws-eks-stack",
25+
path + "/zero-deployable-landing-page",
26+
path + "/zero-deployable-node-backend",
27+
path + "/zero-deployable-react-frontend",
2828
},
2929
},
3030
{

0 commit comments

Comments
 (0)