-
Notifications
You must be signed in to change notification settings - Fork 53
Refactor loading modules and creating project data #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,8 +9,8 @@ import ( | |
| "github.com/aws/aws-sdk-go/aws/credentials" | ||
| "github.com/aws/aws-sdk-go/aws/session" | ||
| "github.com/aws/aws-sdk-go/service/sts" | ||
| "github.com/commitdev/zero/internal/config" | ||
| "github.com/commitdev/zero/internal/config/globalconfig" | ||
| "github.com/commitdev/zero/internal/config/moduleconfig" | ||
| "github.com/commitdev/zero/internal/config/projectconfig" | ||
| "github.com/commitdev/zero/internal/module" | ||
| project "github.com/commitdev/zero/pkg/credentials" | ||
|
|
@@ -38,31 +38,55 @@ func Init(projectName string, outDir string) *projectconfig.ZeroProjectConfig { | |
| projectConfig.Context["ShouldPushRepoUpstream"] = promptPushRepoUpstream() | ||
| projectConfig.Context["GithubRootOrg"] = promptGithubRootOrg() | ||
| projectConfig.Context["githubPersonalToken"] = promptGithubPersonalToken(projectName) | ||
| projectConfig.Modules = chooseStack(getRegistry()) | ||
|
|
||
| // chooseCloudProvider(&projectConfig) | ||
| // fmt.Println(&projectConfig) | ||
| // s := project.GetSecrets(rootDir) | ||
| // fillProviderDetails(&projectConfig, s) | ||
| // fmt.Println(&projectConfig) | ||
| moduleSources := chooseStack(getRegistry()) | ||
| moduleConfigs := loadAllModules(moduleSources) | ||
| for _ = range moduleConfigs { | ||
| // TODO: initialize module structs inside project | ||
| } | ||
|
|
||
| projectParameters := promptAllModules(moduleConfigs) | ||
| for k, v = range projectParameters { | ||
| projectConfig.Context[k] = v | ||
| // TODO: Add parameters to module structs inside project | ||
| } | ||
|
|
||
| promptAllModules(&projectConfig) | ||
| // TODO: load ~/.zero/config.yml (or credentials) | ||
| // TODO: prompt global credentials | ||
|
|
||
| return &projectConfig | ||
| } | ||
|
|
||
| func promptAllModules(projectConfig *projectconfig.ZeroProjectConfig) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This did too much stuff. |
||
| // TODO: do we need to run through the modules and extract first | ||
| // or we need to run through twice, potentially still need to pre-process for global auths | ||
| for _, moduleSource := range projectConfig.Modules { | ||
| mod, _ := module.NewTemplateModule(config.ModuleInstance{Source: moduleSource}) | ||
| err := mod.PromptParams(projectConfig.Context) | ||
| // loadAllModules takes a list of module sources, downloads those modules, and parses their config | ||
| func loadAllModules(moduleSources []string) map[string]moduleconfig.ModuleConfig { | ||
| modules := make(map[string]moduleconfig.ModuleConfig) | ||
|
|
||
| for _, moduleSource := range moduleSources { | ||
| mod, err := module.FetchModule(moduleSource) | ||
| if err != nil { | ||
| exit.Fatal("Unable to load module: %v\n", err) | ||
| } | ||
| modules[mod.Name] = mod | ||
| } | ||
| return modules | ||
| } | ||
|
|
||
| // promptAllModules takes a map of all the modules and prompts the user for values for all the parameters | ||
| func promptAllModules(modules map[string]moduleconfig.ModuleConfig) map[string]string { | ||
| parameterValues := make(map[string]string) | ||
| for _, config := range modules { | ||
| var err error | ||
| parameterValues, err = module.PromptParams(config, parameterValues) | ||
| if err != nil { | ||
| exit.Fatal("Exiting prompt: %v\n", err) | ||
| } | ||
| } | ||
| return parameterValues | ||
| } | ||
|
|
||
| // global configs | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,15 +23,17 @@ import ( | |
| func GenerateModules(cfg *config.GeneratorConfig) { | ||
| var templateModules []*module.TemplateModule | ||
|
|
||
| // Initiate all the modules defined in the config | ||
| for _, moduleConfig := range cfg.Modules { | ||
| mod, err := module.NewTemplateModule(moduleConfig) | ||
| // TODO: Refactor this since the module struct is changing | ||
|
|
||
| if err != nil { | ||
| exit.Error("module failed to load: %s", err) | ||
| } | ||
| templateModules = append(templateModules, mod) | ||
| } | ||
| // Initiate all the modules defined in the config | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented out until we work on generation. |
||
| // for _, moduleConfig := range cfg.Modules { | ||
| //mod, err := module.NewTemplateModule(moduleConfig) | ||
|
|
||
| // if err != nil { | ||
| // exit.Error("module failed to load: %s", err) | ||
| // } | ||
| // templateModules = append(templateModules, mod) | ||
| // } | ||
|
|
||
| // Prompt for module params and execute each of the generator modules | ||
| for _, mod := range templateModules { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,6 @@ import ( | |
| "os/exec" | ||
| "path" | ||
| "regexp" | ||
| "sync" | ||
|
|
||
| "github.com/commitdev/zero/internal/config" | ||
| "github.com/commitdev/zero/internal/config/moduleconfig" | ||
|
|
@@ -26,34 +25,20 @@ type TemplateModule struct { | |
| Config moduleconfig.ModuleConfig | ||
| } | ||
|
|
||
| type ProgressTracking struct { | ||
| sync.Mutex | ||
| downloaded map[string]int | ||
| } | ||
|
|
||
| // Init downloads the remote template files and parses the module config yaml | ||
| func NewTemplateModule(moduleCfg config.ModuleInstance) (*TemplateModule, error) { | ||
| var templateModule TemplateModule | ||
| templateModule.Source = moduleCfg.Source | ||
| templateModule.Params = moduleCfg.Params | ||
| templateModule.Overwrite = moduleCfg.Overwrite | ||
| templateModule.Output = moduleCfg.Output | ||
|
|
||
| p := &ProgressTracking{} | ||
| sourcePath := GetSourceDir(templateModule.Source) | ||
|
|
||
| if !IsLocal(templateModule.Source) { | ||
| err := getter.Get(sourcePath, templateModule.Source, getter.WithProgress(p)) | ||
| // FetchModule downloads the remote module source (or loads the local files) and parses the module config yaml | ||
| func FetchModule(source string) (moduleconfig.ModuleConfig, error) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now accepts a single module source (directory or url) and returns the config of that project. |
||
| config := moduleconfig.ModuleConfig{} | ||
| localPath := GetSourceDir(source) | ||
| if !isLocal(source) { | ||
| err := getter.Get(localPath, source) | ||
| if err != nil { | ||
| return nil, err | ||
| return config, err | ||
| } | ||
| } | ||
|
|
||
| configPath := path.Join(sourcePath, constants.ZeroModuleYml) | ||
| moduleConfig := moduleconfig.LoadModuleConfig(configPath) | ||
| templateModule.Config = *moduleConfig | ||
|
|
||
| return &templateModule, nil | ||
| configPath := path.Join(localPath, constants.ZeroModuleYml) | ||
| config, err := moduleconfig.LoadModuleConfig(configPath) | ||
| return config, err | ||
| } | ||
|
|
||
| func appendProjectEnvToCmdEnv(envMap map[string]string, envList []string) []string { | ||
|
|
@@ -71,6 +56,12 @@ func sanitizePromptResult(str string) string { | |
| return re.ReplaceAllString(str, "") | ||
| } | ||
|
|
||
| // TODO : Use this function signature instead | ||
| // PromptParams renders series of prompt UI based on the config | ||
| func PromptParams(moduleConfig moduleconfig.ModuleConfig, parameters map[string]string) (map[string]string, error) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is for David, you'll have to tie your refactoring in here. |
||
| return map[string]string{}, nil | ||
| } | ||
|
|
||
| // PromptParams renders series of prompt UI based on the config | ||
| func (m *TemplateModule) PromptParams(projectContext map[string]string) error { | ||
| for _, promptConfig := range m.Config.Prompts { | ||
|
|
@@ -128,7 +119,7 @@ func (m *TemplateModule) PromptParams(projectContext map[string]string) error { | |
|
|
||
| // GetSourcePath gets a unique local source directory name. For local modules, it use the local directory | ||
| func GetSourceDir(source string) string { | ||
| if !IsLocal(source) { | ||
| if !isLocal(source) { | ||
| h := md5.New() | ||
| io.WriteString(h, source) | ||
| source = base64.StdEncoding.EncodeToString(h.Sum(nil)) | ||
|
|
@@ -139,7 +130,7 @@ func GetSourceDir(source string) string { | |
| } | ||
|
|
||
| // IsLocal uses the go-getter FileDetector to check if source is a file | ||
| func IsLocal(source string) bool { | ||
| func isLocal(source string) bool { | ||
| pwd := util.GetCwd() | ||
|
|
||
| // ref: https://github.com/hashicorp/go-getter/blob/master/detect_test.go | ||
|
|
@@ -159,16 +150,3 @@ func withPWD(pwd string) func(*getter.Client) error { | |
| return nil | ||
| } | ||
| } | ||
|
|
||
| func (p *ProgressTracking) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) { | ||
| p.Lock() | ||
| defer p.Unlock() | ||
|
|
||
| if p.downloaded == nil { | ||
| p.downloaded = map[string]int{} | ||
| } | ||
|
|
||
| v, _ := p.downloaded[src] | ||
| p.downloaded[src] = v + 1 | ||
| return stream | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package module | ||
|
|
||
| import ( | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestIsLocal(t *testing.T) { | ||
| source := "./tests/test_data/modules" | ||
| res := isLocal(source) | ||
| if !res { | ||
| t.Errorf("Error, source %s SHOULD BE determined as local", source) | ||
| } | ||
|
|
||
| source = "https://github.com/commitdev/my-repo" | ||
| res = isLocal(source) | ||
| if res { | ||
| t.Errorf("Error, source %s SHOULD NOT BE determined as local", source) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,59 +1,24 @@ | ||
| package module | ||
| package module_test | ||
|
|
||
| import ( | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestIsLocal(t *testing.T) { | ||
| source := "./tests/test_data/modules/ci" | ||
| res := IsLocal(source) | ||
| if !res { | ||
| t.Errorf("Error, source %s SHOULD BE determined as local", source) | ||
| } | ||
|
|
||
| source = "https://github.com/zthomas/react-mui-kit" | ||
| res = IsLocal(source) | ||
| if res { | ||
| t.Errorf("Error, source %s SHOULD NOT BE determined as local", source) | ||
| } | ||
| } | ||
| "github.com/commitdev/zero/internal/module" | ||
| ) | ||
|
|
||
| func TestGetSourceDir(t *testing.T) { | ||
| source := "tests/test_data/modules/ci" | ||
| source := "tests/test_data/modules" | ||
| relativeSource := source | ||
| dir := GetSourceDir(source) | ||
| dir := module.GetSourceDir(source) | ||
|
|
||
| t.Log("dir", dir) | ||
| if dir != relativeSource { | ||
| t.Errorf("Error, local sources should not be changed: %s", source) | ||
| } | ||
|
|
||
| source = "github.com/zthomas/react-mui-kit" | ||
| dir = GetSourceDir(source) | ||
| source = "github.com/commitdev/my-repo" | ||
| dir = module.GetSourceDir(source) | ||
| if dir == relativeSource { | ||
| t.Errorf("Error, remote sources should be converted to a local dir: %s", source) | ||
| } | ||
| } | ||
|
|
||
| // var testData = "../../tests/test_data/ci/" | ||
|
|
||
| // func setupTeardown(t *testing.T) func(t *testing.T) { | ||
| // outputPath := "../../tmp/tests" | ||
| // os.RemoveAll(outputPath) | ||
| // return func(t *testing.T) { | ||
| // os.RemoveAll(outputPath) | ||
| // } | ||
| // } | ||
|
|
||
| // func TestDirectoryTemplates(t *testing.T) { | ||
| // teardown := setupTeardown(t) | ||
| // defer teardown(t) | ||
|
|
||
| // // TODO organize test utils and write assertions | ||
| // templator := NewDirTemplator("../../tests/test_data/modules/ci", []string{"{{", "}}"}) | ||
| // var data = map[string]string{ | ||
| // "ci": "github", | ||
| // } | ||
|
|
||
| // templator.ExecuteTemplates(data, false, "tmp", "") | ||
| // } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Being able to call these functions and have a list of all the module configs keyed by module name, and all parameters filled by the user was the core of this refactor, as all this information is required by other logic to come in this function.