Skip to content
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
9 changes: 5 additions & 4 deletions internal/config/projectconfig/project_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import (
)

type ZeroProjectConfig struct {
Name string
Infrastructure Infrastructure // TODO simplify and flatten / rename?
Parameters map[string]string
Modules []string
Name string
ShouldPushRepositories bool
Infrastructure Infrastructure // TODO simplify and flatten / rename?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna remove this Infrastructure struct entirely in another PR

Parameters map[string]string
Modules []string
}

type Infrastructure struct {
Expand Down
87 changes: 66 additions & 21 deletions internal/context/init.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package context

import (
"fmt"
"os"
"path"
"sync"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
Expand All @@ -28,7 +30,7 @@ func Init(outDir string) *projectconfig.ZeroProjectConfig {
projectConfig.Name = getProjectNamePrompt().GetParam(projectConfig.Parameters)

rootDir := path.Join(outDir, projectConfig.Name)
flog.Infof(":tada: Creating project")
flog.Infof(":tada: Initializing project")

err := os.MkdirAll(rootDir, os.ModePerm)
if os.IsExist(err) {
Expand All @@ -37,29 +39,45 @@ func Init(outDir string) *projectconfig.ZeroProjectConfig {
exit.Fatal("Error creating root: %v ", err)
}

prompts := getProjectPrompts(projectConfig.Name)
projectConfig.Parameters["ShouldPushRepoUpstream"] = prompts["ShouldPushRepoUpstream"].GetParam(projectConfig.Parameters)
// Prompting for push-up stream, then conditionally prompting for github
projectConfig.Parameters["GithubRootOrg"] = prompts["GithubRootOrg"].GetParam(projectConfig.Parameters)
personalToken := prompts["githubPersonalToken"].GetParam(projectConfig.Parameters)
if personalToken != "" && personalToken != globalconfig.GetUserCredentials(projectConfig.Name).AccessToken {
projectConfig.Parameters["githubPersonalToken"] = personalToken
projectCredential := globalconfig.GetUserCredentials(projectConfig.Name)
projectCredential.GithubResourceConfig.AccessToken = personalToken
globalconfig.Save(projectCredential)
}
moduleSources := chooseStack(getRegistry())
moduleConfigs := loadAllModules(moduleSources)
for _ = range moduleConfigs {
// TODO: initialize module structs inside project
}

prompts := getProjectPrompts(projectConfig.Name, moduleConfigs)

initParams := make(map[string]string)
projectConfig.ShouldPushRepositories = true
initParams["ShouldPushRepositories"] = prompts["ShouldPushRepositories"].GetParam(initParams)
if initParams["ShouldPushRepositories"] == "n" {
projectConfig.ShouldPushRepositories = false
}

// Prompting for push-up stream, then conditionally prompting for github
initParams["GithubRootOrg"] = prompts["GithubRootOrg"].GetParam(initParams)
initParams["GithubPersonalToken"] = prompts["GithubPersonalToken"].GetParam(initParams)
if initParams["GithubRootOrg"] != "" && initParams["GithubPersonalToken"] != globalconfig.GetUserCredentials(projectConfig.Name).AccessToken {
projectCredential := globalconfig.GetUserCredentials(projectConfig.Name)
projectCredential.GithubResourceConfig.AccessToken = initParams["GithubPersonalToken"]
globalconfig.Save(projectCredential)
}

projectParameters := promptAllModules(moduleConfigs)
for k, v := range projectParameters {
projectConfig.Parameters[k] = v
// TODO: Add parameters to module structs inside project
}

for moduleName, _ := range moduleConfigs {
// @TODO : Uncomment when this struct is implemented
repoName := prompts[moduleName].GetParam(initParams)
repoURL := fmt.Sprintf("%s/%s", initParams["GithubRootOrg"], repoName)
//projectConfig.Modules[moduleName].Files.Directory = prompts[moduleName].GetParam(initParams)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll uncomment this after Thiago's PR is merged.

//projectConfig.Modules[moduleName].Files.Repository = repoURL
fmt.Println(repoURL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray print command

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, reminder that that code needs to be filled in.

}

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

Expand All @@ -70,8 +88,15 @@ func Init(outDir string) *projectconfig.ZeroProjectConfig {
func loadAllModules(moduleSources []string) map[string]moduleconfig.ModuleConfig {
modules := make(map[string]moduleconfig.ModuleConfig)

wg := sync.WaitGroup{}
wg.Add(len(moduleSources))
for _, moduleSource := range moduleSources {
go module.FetchModule(moduleSource, &wg)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fetching will be done in parallel now

}
wg.Wait()

for _, moduleSource := range moduleSources {
mod, err := module.FetchModule(moduleSource)
mod, err := module.ParseModuleConfig(moduleSource)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split the parsing out from the fetching

if err != nil {
exit.Fatal("Unable to load module: %v\n", err)
}
Expand Down Expand Up @@ -103,36 +128,56 @@ func getProjectNamePrompt() PromptHandler {
Default: "",
},
NoCondition,
NoValidation,
}
}

func getProjectPrompts(projectName string) map[string]PromptHandler {
return map[string]PromptHandler{
"ShouldPushRepoUpstream": {
func getProjectPrompts(projectName string, modules map[string]moduleconfig.ModuleConfig) map[string]PromptHandler {
handlers := map[string]PromptHandler{
"ShouldPushRepositories": {
moduleconfig.Parameter{
Field: "ShouldPushRepoUpstream",
Field: "ShouldPushRepositories",
Label: "Should the created projects be checked into github automatically? (y/n)",
Default: "y",
},
NoCondition,
SpecificValueValidation("y", "n"),
},
"GithubRootOrg": {
moduleconfig.Parameter{
Field: "GithubRootOrg",
Label: "What's the root of the github org to create repositories in?",
Default: "github.com/",
},
KeyMatchCondition("ShouldPushRepoUpstream", "y"),
KeyMatchCondition("ShouldPushRepositories", "y"),
NoValidation,
},
"githubPersonalToken": {
"GithubPersonalToken": {
moduleconfig.Parameter{
Field: "githubPersonalToken",
Field: "GithubPersonalToken",
Label: "Github Personal Access Token with access to the above organization",
Default: globalconfig.GetUserCredentials(projectName).AccessToken,
},
KeyMatchCondition("ShouldPushRepoUpstream", "y"),
KeyMatchCondition("ShouldPushRepositories", "y"),
NoValidation,
},
}

for moduleName, module := range modules {
label := fmt.Sprintf("What do you want to call the %s project?", moduleName)

handlers[moduleName] = PromptHandler{
moduleconfig.Parameter{
Field: moduleName,
Label: label,
Default: module.OutputDir,
},
NoCondition,
NoValidation,
}
}

return handlers
}

func chooseCloudProvider(projectConfig *projectconfig.ZeroProjectConfig) {
Expand Down
25 changes: 23 additions & 2 deletions internal/context/prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"regexp"
"strings"

"github.com/commitdev/zero/internal/config/moduleconfig"
"github.com/commitdev/zero/pkg/util/exit"
Expand All @@ -15,17 +16,34 @@ import (
type PromptHandler struct {
moduleconfig.Parameter
Condition func(map[string]string) bool
Validate func(string) error
Copy link
Contributor

@davidcheung davidcheung Jun 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 maybe later on we can implement some type of openapi schema validation, then user can supply that on the module side and we can consume from Parameter struct as well

}

func NoCondition(map[string]string) bool {
return true
}

func KeyMatchCondition(key string, value string) func(map[string]string) bool {
return func(param map[string]string) bool {
return param[key] == value
}
}

func NoValidation(string) error {
return nil
}

func SpecificValueValidation(values ...string) func(string) error {
return func(checkValue string) error {
for _, allowedValue := range values {
if checkValue == allowedValue {
return nil
}
}
return fmt.Errorf("Please choose one of %s", strings.Join(values, "/"))
}
}

// TODO: validation / allow prompt retry ...etc
func (p PromptHandler) GetParam(projectParams map[string]string) string {
var err error
Expand All @@ -40,7 +58,7 @@ func (p PromptHandler) GetParam(projectParams map[string]string) string {
} else if p.Parameter.Value != "" {
result = p.Parameter.Value
} else {
err, result = promptParameter(p.Parameter)
err, result = promptParameter(p)
}
if err != nil {
exit.Fatal("Exiting prompt: %v\n", err)
Expand All @@ -51,7 +69,8 @@ func (p PromptHandler) GetParam(projectParams map[string]string) string {
return ""
}

func promptParameter(param moduleconfig.Parameter) (error, string) {
func promptParameter(prompt PromptHandler) (error, string) {
param := prompt.Parameter
label := param.Label
if param.Label == "" {
label = param.Field
Expand All @@ -72,6 +91,7 @@ func promptParameter(param moduleconfig.Parameter) (error, string) {
Label: label,
Default: defaultValue,
AllowEdit: true,
Validate: prompt.Validate,
}
result, err = prompt.Run()
}
Expand Down Expand Up @@ -119,6 +139,7 @@ func PromptModuleParams(moduleConfig moduleconfig.ModuleConfig, parameters map[s
promptHandler := PromptHandler{
promptConfig,
NoCondition,
NoValidation,
}
result := promptHandler.GetParam(parameters)

Expand Down
3 changes: 3 additions & 0 deletions internal/context/prompts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestGetParam(t *testing.T) {
prompt := context.PromptHandler{
param,
context.NoCondition,
context.NoValidation,
}

result := prompt.GetParam(projectParams)
Expand All @@ -35,6 +36,7 @@ func TestGetParam(t *testing.T) {
prompt := context.PromptHandler{
param,
context.NoCondition,
context.NoValidation,
}

result := prompt.GetParam(map[string]string{
Expand All @@ -52,6 +54,7 @@ func TestGetParam(t *testing.T) {
prompt := context.PromptHandler{
param,
context.NoCondition,
context.NoValidation,
}

result := prompt.GetParam(projectParams)
Expand Down
17 changes: 13 additions & 4 deletions internal/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"log"
"path"
"regexp"
"sync"

"github.com/commitdev/zero/internal/config"
"github.com/commitdev/zero/internal/config/moduleconfig"
"github.com/commitdev/zero/internal/constants"
"github.com/commitdev/zero/internal/util"
"github.com/commitdev/zero/pkg/util/exit"
"github.com/hashicorp/go-getter"
)

Expand All @@ -21,17 +23,24 @@ type TemplateModule struct {
Config moduleconfig.ModuleConfig
}

// FetchModule downloads the remote module source (or loads the local files) and parses the module config yaml
func FetchModule(source string) (moduleconfig.ModuleConfig, error) {
config := moduleconfig.ModuleConfig{}
// FetchModule downloads the remote module source if necessary. Meant to be run in a goroutine.
func FetchModule(source string, wg *sync.WaitGroup) {
defer wg.Done()

localPath := GetSourceDir(source)
if !isLocal(source) {
err := getter.Get(localPath, source)
if err != nil {
return config, err
exit.Fatal("Failed to fetch remote module from %s: %v\n", source, err)
}
}
return
}

// ParseModuleConfig loads the local config file for a module and parses the yaml
func ParseModuleConfig(source string) (moduleconfig.ModuleConfig, error) {
localPath := GetSourceDir(source)
config := moduleconfig.ModuleConfig{}
configPath := path.Join(localPath, constants.ZeroModuleYml)
config, err := moduleconfig.LoadModuleConfig(configPath)
return config, err
Expand Down
2 changes: 1 addition & 1 deletion internal/module/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestNewTemplateModule(t *testing.T) {
var mod moduleconfig.ModuleConfig

t.Run("Loading module from source", func(t *testing.T) {
mod, _ = module.FetchModule(testModuleSource)
mod, _ = module.ParseModuleConfig(testModuleSource)

assert.Equal(t, "CI templates", mod.Name)
})
Expand Down