-
Notifications
You must be signed in to change notification settings - Fork 52
/
apply.go
129 lines (106 loc) · 4.24 KB
/
apply.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package apply
import (
"fmt"
"path/filepath"
"log"
"os/exec"
"path"
"strings"
"github.com/commitdev/zero/internal/module"
"github.com/commitdev/zero/internal/util"
"github.com/hashicorp/terraform/dag"
"github.com/commitdev/zero/internal/config/globalconfig"
"github.com/commitdev/zero/internal/config/projectconfig"
"github.com/commitdev/zero/pkg/util/exit"
"github.com/commitdev/zero/pkg/util/flog"
"github.com/manifoldco/promptui"
)
func Apply(rootDir string, configPath string, environments []string) {
if strings.Trim(configPath, " ") == "" {
exit.Fatal("config path cannot be empty!")
}
configFilePath := path.Join(rootDir, configPath)
projectConfig := projectconfig.LoadConfig(configFilePath)
if len(environments) == 0 {
fmt.Println(`Choose the environments to apply. This will create infrastructure, CI pipelines, etc.
At this point, real things will be generated that may cost money!
Only a single environment may be suitable for an initial test, but for a real system we suggest setting up both staging and production environments.`)
environments = promptEnvironments()
}
flog.Infof(":tada: Bootstrapping project %s. Please use the zero-project.yml file to modify the project as needed.", projectConfig.Name)
flog.Infof("Cloud provider: %s", "AWS") // will this come from the config?
flog.Infof("Runtime platform: %s", "Kubernetes")
flog.Infof("Infrastructure executor: %s", "Terraform")
applyAll(rootDir, *projectConfig, environments)
// TODO Summary
flog.Infof(":check_mark_button: Done - Summary goes here.")
}
func applyAll(dir string, projectConfig projectconfig.ZeroProjectConfig, applyEnvironments []string) {
environmentArg := fmt.Sprintf("ENVIRONMENT=%s", strings.Join(applyEnvironments, ","))
graph := projectConfig.GetDAG()
// Walk the graph of modules and run `make`
root := []dag.Vertex{projectconfig.GraphRootName}
graph.DepthFirstWalk(root, func(v dag.Vertex, depth int) error {
// Don't process the root
if depth == 0 {
return nil
}
name := v.(string)
mod := projectConfig.Modules[name]
// Add env vars for the makefile
envList := []string{
environmentArg,
fmt.Sprintf("PROJECT_DIR=%s", path.Join(dir, mod.Files.Directory)),
fmt.Sprintf("REPOSITORY=%s", mod.Files.Repository),
}
modulePath := module.GetSourceDir(mod.Files.Source)
// Passed in `dir` will only be used to find the project path, not the module path,
// unless the module path is relative
if module.IsLocal(mod.Files.Source) && !filepath.IsAbs(modulePath) {
modulePath = filepath.Join(dir, modulePath)
}
// TODO: in the case user lost the `/tmp` (module source dir), this will fail
// and we should redownload the module for the user
modConfig, err := module.ParseModuleConfig(modulePath)
if err != nil {
exit.Fatal("Failed to load module config, credentials cannot be injected properly")
}
// Get project credentials for the makefile
credentials := globalconfig.GetProjectCredentials(projectConfig.Name)
credentialEnvs := credentials.SelectedVendorsCredentialsAsEnv(modConfig.RequiredCredentials)
envList = util.AppendProjectEnvToCmdEnv(mod.Parameters, envList)
envList = util.AppendProjectEnvToCmdEnv(credentialEnvs, envList)
util.ExecuteCommand(exec.Command("make"), modulePath, envList)
return nil
})
}
// promptEnvironments Prompts the user for the environments to apply against and returns a slice of strings representing the environments
func promptEnvironments() []string {
items := map[string][]string{
"Staging ": {"staging"},
"Production": {"production"},
"Both Staging and Production": {"staging", "production"},
}
var labels []string
for label := range items {
labels = append(labels, label)
}
providerPrompt := promptui.Select{
Label: "Environments",
Items: labels,
}
_, providerResult, err := providerPrompt.Run()
if err != nil {
log.Fatalf("Prompt failed %v\n", err)
panic(err)
}
return items[providerResult]
}
func validateEnvironments(applyEnvironments []string) {
// Strict for now, we can brainstorm how much we want to support custom environments later
for _, env := range applyEnvironments {
if env != "staging" && env != "production" {
exit.Fatal("The currently supported environments are \"staging\" and \"production\"")
}
}
}