Skip to content

Commit 7f4c7a3

Browse files
[SEMVER-MAJOR] condition support to module params (#350)
* [SEMVER-MAJOR] condition support to module params changes includes - removing global config - module config’s parameter to support condition - module config’s parameter to support custom typed prompts - prompts to not return value, instead update map(can support multi-value) * remove credentials * dynamically populate from struct * allow overwriting the env-var while apply * add comments to public functions * address comments * project definition * Update docs/module-definition.md Co-authored-by: Bill Monkman <bmonkman@gmail.com> * Update docs/project-definition.md Co-authored-by: Bill Monkman <bmonkman@gmail.com> * better error message to users * explain template parameters * condition clarification between module and param Co-authored-by: Bill Monkman <bmonkman@gmail.com>
1 parent 7c3a230 commit 7f4c7a3

File tree

24 files changed

+643
-622
lines changed

24 files changed

+643
-622
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ You need to [register a new domain](https://docs.aws.amazon.com/Route53/latest/D
101101
102102
___
103103

104+
### Building blocks of Zero
105+
106+
### Project Definition:
107+
Each project is defined by this project definition file, this manifest contains your project details, and is the source of truth for the templating(`zero create`) and provision(`zero apply`) steps.
108+
109+
See [`zero-project.yml` reference](./docs/project-definition.md) for details.
110+
### Module Definition
111+
Module definition defines the information needed for the module to run (`zero apply`).
112+
Also declares dependency used to determine the order of execution with other modules.
113+
114+
See [`zero-module.yml` reference](./docs/module-definition.md) for details.
115+
___
104116
## Using zero to spin up your own stack
105117

106118
Using Zero to spin up your infrastructure and application is easy and straightforward. Using just a few commands, you can configure and deploy your very own scalable, high-performance, production-ready infrastructure.

cmd/create.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"path"
66
"strings"
77

8-
"github.com/commitdev/zero/internal/config/globalconfig"
98
"github.com/commitdev/zero/internal/config/projectconfig"
109
"github.com/commitdev/zero/internal/constants"
1110
"github.com/commitdev/zero/internal/generate"
@@ -47,9 +46,12 @@ func Create(dir string, createConfigPath string) {
4746
if projectConfig.ShouldPushRepositories {
4847
flog.Infof(":up_arrow: Done Rendering - committing repositories to version control.")
4948

50-
globalConfig := globalconfig.GetProjectCredentials(projectConfig.Name)
5149
for _, module := range projectConfig.Modules {
52-
vcs.InitializeRepository(module.Files.Repository, globalConfig.GithubResourceConfig.AccessToken)
50+
err, githubApiKey := projectconfig.ReadVendorCredentialsFromModule(module, "github")
51+
if err != nil {
52+
flog.Errorf(err.Error())
53+
}
54+
vcs.InitializeRepository(module.Files.Repository, githubApiKey)
5355
}
5456
} else {
5557
flog.Infof(":up_arrow: Done Rendering - you will need to commit the created projects to version control.")

docs/module-definition.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## Module Definition: `zero-module.yml`
2+
This file is the definition of a Zero module. It contains a list of all the required parameters to be able to prompt a user for choices during `zero init`, information about how to template the contents of the module during `zero create`, and the information needed for the module to run (`zero apply`).
3+
It also declares the module's dependencies to determine the order of execution in relation to other modules.
4+
5+
| Parameters | type | Description |
6+
|---------------|-----------------|--------------------------------------------------|
7+
| `name` | string | Name of module |
8+
| `description` | string | Description of the module |
9+
| `template` | template | default settings for templating out the module |
10+
| `author` | string | Author of the module |
11+
| `icon` | string | Path to logo image |
12+
| `parameters` | list(Parameter) | Parameters to prompt users |
13+
14+
15+
### Template
16+
| Parameters | Type | Description |
17+
|--------------|---------|-----------------------------------------------------------------------|
18+
| `strictMode` | boolean | whether strict mode is enabled |
19+
| `delimiters` | tuple | A tuple of open delimiter and ending delimiter eg: `<%` and `%>` |
20+
| `inputDir` | string | Folder to template from the module, becomes the module root for users |
21+
| `outputDir` | string | local directory name for the module, gets commited to version control |
22+
23+
### Condition(module)
24+
Module conditions are considered during template phase (`zero create`), based on parameters supplied from project-definition,
25+
modules can decide to have specific files ignored from the user's module. For example if user picks `userAuth: no`, we can ignore the auth resources via templating.
26+
27+
| Parameters | Type | Description |
28+
|--------------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
29+
| `action` | enum(string) | type of condition, currently supports [`ignoreFile`] |
30+
| `matchField` | string | Allows you to condition prompt based on another parameter's value |
31+
| `WhenValue` | string | Matches for this value to satisfy the condition |
32+
| `data` | list(string) | Supply extra data for condition to run `ignoreFile`: provide list of paths (file or directory path) to omit from module when condition is satisfied |
33+
34+
### Parameter:
35+
Parameter defines the prompt during zero-init.
36+
There are multiple ways of obtaining the value for each parameter.
37+
Parameters may have `Conditions` and must be fulfilled when supplied, otherwise it skips the field entirely.
38+
39+
The precedence for different types of parameter prompts are as follow.
40+
1. Execute
41+
2. type: specific ways of obtaining values (in AWS credential case it will set 2 values to the map)
42+
3. value: directly assigns a value to a parameter
43+
4. prompt: requires users to select an option OR input a string
44+
Note: Default is supplied as the starting point of the user's manual input (Not when value passed in is empty)
45+
46+
| Parameters | Type | Description |
47+
|-----------------------|-----------------|---------------------------------------------------------------------------------------------------------------------------|
48+
| `field` | string | key to store result for project definition |
49+
| `label` | string | displayed name for the prompt |
50+
| `options` | list(string) | A list of values for users to pick from |
51+
| `default` | string | Defaults to this value during prompt |
52+
| `value` | string | Skips prompt entirely when set |
53+
| `info` | string | Displays during prompt as extra information guiding user's input |
54+
| `fieldValidation` | Validation | Validations for the prompt value |
55+
| `type` | enum(string) | Built in custom prompts: currently supports [`AWSProfilePicker`] |
56+
| `execute` | string | executes commands and takes stdout as prompt result |
57+
| `omitFromProjectFile` | bool | Field is skipped from adding to project definition |
58+
| `conditions` | list(Condition) | Conditions for prompt to run, if supplied all conditions must pass |
59+
| `envVarName` | string | During `zero apply` parameters are available as env-vars, defaults to field name but can be overwritten with `envVarName` |
60+
61+
### Condition(paramters)
62+
Parameters conditions are considered while running user prompts, prompts are
63+
executed in order of the yml, and will be skipped if conditions are not satisfied.
64+
For example if a user decide to not use circleCI, condition can be used to skip the circleCI_api_key prompt.
65+
66+
| Parameters | Type | Description |
67+
|--------------|--------------|-------------------------------------------------------------------|
68+
| `action` | enum(string) | type of condition, currently supports [`KeyMatchCondition`] |
69+
| `matchField` | string | Allows you to condition prompt based on another parameter's value |
70+
| `WhenValue` | string | Matches for this value to satisfy the condition |
71+
| `data` | list(string) | Supply extra data for condition to run |
72+
73+
### Validation
74+
75+
| Parameters | type | Description |
76+
|----------------|--------------|-------------------------------------|
77+
| `type` | enum(string) | Currently supports [`regex`] |
78+
| `value` | string | Regular expression string |
79+
| `errorMessage` | string | Error message when validation fails |

docs/project-definition.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
### Project Definition: `zero-project.yml`
2+
Each project is defined by this file. This manifest reflects all the options a user chose during the `zero init` step. It defines which modules are part of the project, each of their parameters, and is the source of truth for the templating (`zero create`) and provision (`zero apply`) steps.
3+
4+
_Note: This file contains credentials, so make sure it is not shared with others._
5+
6+
| Parameters | Type | Description |
7+
|--------------------------|--------------|------------------------------------------------|
8+
| `name` | string | name of the project |
9+
| `shouldPushRepositories` | boolean | whether to push the modules to version control |
10+
| `modules` | map(modules) | a map containing modules of your project |
11+
12+
13+
### Modules
14+
| Parameters | Type | Description |
15+
|--------------|-----------------|-------------------------------------------------------------------------|
16+
| `parameters` | map(string) | key-value map of all the parameters to run the module |
17+
| `files` | File | Stores information such as source-module location and destination |
18+
| `dependsOn` | list(string) | a list of dependencies that should be fulfilled before this module |
19+
| `conditions` | list(condition) | conditions to apply while templating out the module based on parameters |
20+
21+
### Condition
22+
| Parameters | Type | Description |
23+
|--------------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
24+
| `action` | enum(string) | type of condition, currently supports [`ignoreFile`] |
25+
| `matchField` | string | Allows you to condition prompt based on another parameter's value |
26+
| `WhenValue` | string | Matches for this value to satisfy the condition |
27+
| `data` | list(string) | Supply extra data for condition to run `ignoreFile`: provide list of paths (file or directory path) to omit from module when condition is satisfied |

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
github.com/matryer/is v1.3.0 // indirect
2323
github.com/mattn/go-colorable v0.1.2 // indirect
2424
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
25+
github.com/pkg/errors v0.9.1
2526
github.com/sirupsen/logrus v1.2.0
2627
github.com/spf13/cobra v0.0.6
2728
github.com/stretchr/testify v1.5.1

internal/apply/apply.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/commitdev/zero/internal/util"
1414
"github.com/hashicorp/terraform/dag"
1515

16-
"github.com/commitdev/zero/internal/config/globalconfig"
1716
"github.com/commitdev/zero/internal/config/projectconfig"
1817
"github.com/commitdev/zero/pkg/util/exit"
1918
"github.com/commitdev/zero/pkg/util/flog"
@@ -87,11 +86,8 @@ func applyAll(dir string, projectConfig projectconfig.ZeroProjectConfig, applyEn
8786
exit.Fatal("Failed to load module config, credentials cannot be injected properly")
8887
}
8988

90-
// Get project credentials for the makefile
91-
credentials := globalconfig.GetProjectCredentials(projectConfig.Name)
92-
credentialEnvs := credentials.SelectedVendorsCredentialsAsEnv(modConfig.RequiredCredentials)
93-
envList = util.AppendProjectEnvToCmdEnv(mod.Parameters, envList)
94-
envList = util.AppendProjectEnvToCmdEnv(credentialEnvs, envList)
89+
envVarTranslationMap := modConfig.GetParamEnvVarTranslationMap()
90+
envList = util.AppendProjectEnvToCmdEnv(mod.Parameters, envList, envVarTranslationMap)
9591
flog.Debugf("Env injected: %#v", envList)
9692
flog.Infof("Executing apply command for %s...", modConfig.Name)
9793
util.ExecuteCommand(exec.Command("make"), modulePath, envList)
@@ -160,7 +156,12 @@ func summarizeAll(dir string, projectConfig projectconfig.ZeroProjectConfig, app
160156
}
161157
flog.Debugf("Loaded module: %s from %s", name, modulePath)
162158

163-
envList = util.AppendProjectEnvToCmdEnv(mod.Parameters, envList)
159+
modConfig, err := module.ParseModuleConfig(modulePath)
160+
if err != nil {
161+
exit.Fatal("Failed to load module config, credentials cannot be injected properly")
162+
}
163+
envVarTranslationMap := modConfig.GetParamEnvVarTranslationMap()
164+
envList = util.AppendProjectEnvToCmdEnv(mod.Parameters, envList, envVarTranslationMap)
164165
flog.Debugf("Env injected: %#v", envList)
165166
util.ExecuteCommand(exec.Command("make", "summary"), modulePath, envList)
166167
return nil

internal/apply/apply_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,11 @@ func TestApply(t *testing.T) {
3838
assert.NoError(t, err)
3939
assert.Equal(t, "baz: qux\n", string(content))
4040
})
41+
42+
t.Run("Zero apply honors the envVarName overwrite from module definition", func(t *testing.T) {
43+
content, err := ioutil.ReadFile(filepath.Join(tmpDir, "project1/feature.out"))
44+
assert.NoError(t, err)
45+
assert.Equal(t, "envVarName of viaEnvVarName: baz\n", string(content))
46+
})
47+
4148
}

internal/config/globalconfig/global_config.go

Lines changed: 0 additions & 183 deletions
This file was deleted.

0 commit comments

Comments
 (0)