Skip to content

Commit 10d851b

Browse files
authored
Merge pull request #164 from commitdev/global-cred-prompt
Global cred prompt
2 parents 942713d + dea7ac1 commit 10d851b

File tree

7 files changed

+128
-25
lines changed

7 files changed

+128
-25
lines changed

internal/config/globalconfig/global_config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func readOrCreateUserCredentialsFile() []byte {
9393
return data
9494
}
9595

96-
func GetUserCredentials(targetProjectName string) ProjectCredential {
96+
func GetProjectCredentials(targetProjectName string) ProjectCredential {
9797
projects := LoadUserCredentials()
9898

9999
if val, ok := projects[targetProjectName]; ok {

internal/config/globalconfig/global_config_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestReadOrCreateUserCredentialsFile(t *testing.T) {
4949
_, fileStateErr := os.Stat(credPath)
5050
assert.True(t, os.IsNotExist(fileStateErr), "File should not exist")
5151
// attempting to read the file should create the file
52-
globalconfig.GetUserCredentials("any-project")
52+
globalconfig.GetProjectCredentials("any-project")
5353

5454
stats, err := os.Stat(credPath)
5555
assert.False(t, os.IsNotExist(err), "File should be created")
@@ -63,7 +63,7 @@ func TestGetUserCredentials(t *testing.T) {
6363

6464
t.Run("Fixture file should have existing project with creds", func(t *testing.T) {
6565
projectName := "my-project"
66-
project := globalconfig.GetUserCredentials(projectName)
66+
project := globalconfig.GetProjectCredentials(projectName)
6767

6868
// Reading from fixtures: tests/test_data/configs/credentials.yml
6969
assert.Equal(t, "AKIAABCD", project.AWSResourceConfig.AccessKeyId)
@@ -74,7 +74,7 @@ func TestGetUserCredentials(t *testing.T) {
7474

7575
t.Run("Fixture file should support multiple projects", func(t *testing.T) {
7676
projectName := "another-project"
77-
project := globalconfig.GetUserCredentials(projectName)
77+
project := globalconfig.GetProjectCredentials(projectName)
7878
assert.Equal(t, "654", project.GithubResourceConfig.AccessToken)
7979
})
8080
}
@@ -86,18 +86,18 @@ func TestEditUserCredentials(t *testing.T) {
8686

8787
t.Run("Should create new project if not exist", func(t *testing.T) {
8888
projectName := "test-project3"
89-
project := globalconfig.GetUserCredentials(projectName)
89+
project := globalconfig.GetProjectCredentials(projectName)
9090
project.AWSResourceConfig.AccessKeyId = "TEST_KEY_ID_1"
9191
globalconfig.Save(project)
92-
newKeyID := globalconfig.GetUserCredentials(projectName).AWSResourceConfig.AccessKeyId
92+
newKeyID := globalconfig.GetProjectCredentials(projectName).AWSResourceConfig.AccessKeyId
9393
assert.Equal(t, "TEST_KEY_ID_1", newKeyID)
9494
})
9595
t.Run("Should edit old project if already exist", func(t *testing.T) {
9696
projectName := "my-project"
97-
project := globalconfig.GetUserCredentials(projectName)
97+
project := globalconfig.GetProjectCredentials(projectName)
9898
project.AWSResourceConfig.AccessKeyId = "EDITED_ACCESS_KEY_ID"
9999
globalconfig.Save(project)
100-
newKeyID := globalconfig.GetUserCredentials(projectName).AWSResourceConfig.AccessKeyId
100+
newKeyID := globalconfig.GetProjectCredentials(projectName).AWSResourceConfig.AccessKeyId
101101
assert.Equal(t, "EDITED_ACCESS_KEY_ID", newKeyID)
102102
})
103103
}

internal/config/moduleconfig/module_config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type ModuleConfig struct {
1212
Description string
1313
Author string
1414
TemplateConfig `yaml:"template"`
15-
RequiredCredentials []string
15+
RequiredCredentials []string `yaml:"requiredCredentials"`
1616
Parameters []Parameter
1717
}
1818

internal/context/init.go

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,10 @@ func Init(outDir string) *projectconfig.ZeroProjectConfig {
5454

5555
// Prompting for push-up stream, then conditionally prompting for github
5656
initParams["GithubRootOrg"] = prompts["GithubRootOrg"].GetParam(initParams)
57-
initParams["GithubPersonalToken"] = prompts["GithubPersonalToken"].GetParam(initParams)
58-
if initParams["GithubRootOrg"] != "" && initParams["GithubPersonalToken"] != globalconfig.GetUserCredentials(projectConfig.Name).AccessToken {
59-
projectCredential := globalconfig.GetUserCredentials(projectConfig.Name)
60-
projectCredential.GithubResourceConfig.AccessToken = initParams["GithubPersonalToken"]
61-
globalconfig.Save(projectCredential)
62-
}
63-
57+
projectCredentials := globalconfig.GetProjectCredentials(projectConfig.Name)
58+
credentialPrompts := getCredentialPrompts(projectCredentials, moduleConfigs)
59+
projectCredentials = promptCredentialsAndFillProjectCreds(credentialPrompts, projectCredentials)
60+
globalconfig.Save(projectCredentials)
6461
projectParameters := promptAllModules(moduleConfigs)
6562

6663
// Map parameter values back to specific modules
@@ -84,6 +81,7 @@ func Init(outDir string) *projectconfig.ZeroProjectConfig {
8481

8582
// TODO : Write the project config file. For now, print.
8683
pp.Println(projectConfig)
84+
pp.Print(projectCredentials)
8785

8886
// TODO: load ~/.zero/config.yml (or credentials)
8987
// TODO: prompt global credentials
@@ -159,15 +157,6 @@ func getProjectPrompts(projectName string, modules map[string]moduleconfig.Modul
159157
KeyMatchCondition("ShouldPushRepositories", "y"),
160158
NoValidation,
161159
},
162-
"GithubPersonalToken": {
163-
moduleconfig.Parameter{
164-
Field: "GithubPersonalToken",
165-
Label: "Github Personal Access Token with access to the above organization",
166-
Default: globalconfig.GetUserCredentials(projectName).AccessToken,
167-
},
168-
KeyMatchCondition("ShouldPushRepositories", "y"),
169-
NoValidation,
170-
},
171160
}
172161

173162
for moduleName, module := range modules {
@@ -187,6 +176,71 @@ func getProjectPrompts(projectName string, modules map[string]moduleconfig.Modul
187176
return handlers
188177
}
189178

179+
func getCredentialPrompts(projectCredentials globalconfig.ProjectCredential, moduleConfigs map[string]moduleconfig.ModuleConfig) map[string][]PromptHandler {
180+
var uniqueVendors []string
181+
for _, module := range moduleConfigs {
182+
uniqueVendors = appendToSet(uniqueVendors, module.RequiredCredentials)
183+
}
184+
// map is to keep track of which vendor they belong to, to fill them back into the projectConfig
185+
prompts := map[string][]PromptHandler{}
186+
for _, vendor := range uniqueVendors {
187+
prompts[vendor] = mapVendorToPrompts(projectCredentials, vendor)
188+
}
189+
return prompts
190+
}
191+
192+
func mapVendorToPrompts(projectCred globalconfig.ProjectCredential, vendor string) []PromptHandler {
193+
var prompts []PromptHandler
194+
195+
switch vendor {
196+
case "aws":
197+
awsPrompts := []PromptHandler{
198+
{
199+
moduleconfig.Parameter{
200+
Field: "accessKeyId",
201+
Label: "AWS Access Key ID",
202+
Default: projectCred.AWSResourceConfig.AccessKeyId,
203+
},
204+
NoCondition,
205+
NoValidation,
206+
},
207+
{
208+
moduleconfig.Parameter{
209+
Field: "secretAccessKey",
210+
Label: "AWS Secret access key",
211+
Default: projectCred.AWSResourceConfig.SecretAccessKey,
212+
},
213+
NoCondition,
214+
NoValidation,
215+
},
216+
}
217+
prompts = append(prompts, awsPrompts...)
218+
case "github":
219+
githubPrompt := PromptHandler{
220+
moduleconfig.Parameter{
221+
Field: "accessToken",
222+
Label: "Github Personal Access Token with access to the above organization",
223+
Default: projectCred.GithubResourceConfig.AccessToken,
224+
},
225+
NoCondition,
226+
NoValidation,
227+
}
228+
prompts = append(prompts, githubPrompt)
229+
case "circleci":
230+
circleCiPrompt := PromptHandler{
231+
moduleconfig.Parameter{
232+
Field: "apiKey",
233+
Label: "Circleci api key for CI/CD",
234+
Default: projectCred.CircleCiResourceConfig.ApiKey,
235+
},
236+
NoCondition,
237+
NoValidation,
238+
}
239+
prompts = append(prompts, circleCiPrompt)
240+
}
241+
return prompts
242+
}
243+
190244
func chooseCloudProvider(projectConfig *projectconfig.ZeroProjectConfig) {
191245
// @TODO move options into configs
192246
providerPrompt := promptui.Select{

internal/context/prompts.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88
"regexp"
99
"strings"
1010

11+
"github.com/commitdev/zero/internal/config/globalconfig"
1112
"github.com/commitdev/zero/internal/config/moduleconfig"
1213
"github.com/commitdev/zero/pkg/util/exit"
1314
"github.com/manifoldco/promptui"
15+
"gopkg.in/yaml.v2"
1416
)
1517

1618
type PromptHandler struct {
@@ -147,3 +149,41 @@ func PromptModuleParams(moduleConfig moduleconfig.ModuleConfig, parameters map[s
147149
}
148150
return parameters, nil
149151
}
152+
153+
func promptCredentialsAndFillProjectCreds(credentialPrompts map[string][]PromptHandler, credentials globalconfig.ProjectCredential) globalconfig.ProjectCredential {
154+
promptsValues := map[string]map[string]string{}
155+
156+
for vendor, prompts := range credentialPrompts {
157+
vendorPromptValues := map[string]string{}
158+
159+
// vendors like AWS have multiple prompts (accessKeyId and secretAccessKey)
160+
for _, prompt := range prompts {
161+
vendorPromptValues[prompt.Field] = prompt.GetParam(map[string]string{})
162+
}
163+
promptsValues[vendor] = vendorPromptValues
164+
}
165+
166+
// FIXME: what is a good way to dynamically modify partial data of a struct
167+
// current just marashing to yaml, then unmarshaling into the base struct
168+
yamlContent, _ := yaml.Marshal(promptsValues)
169+
yaml.Unmarshal(yamlContent, &credentials)
170+
return credentials
171+
}
172+
173+
func appendToSet(set []string, toAppend []string) []string {
174+
for _, appendee := range toAppend {
175+
if !itemInSlice(set, appendee) {
176+
set = append(set, appendee)
177+
}
178+
}
179+
return set
180+
}
181+
182+
func itemInSlice(slice []string, target string) bool {
183+
for _, item := range slice {
184+
if item == target {
185+
return true
186+
}
187+
}
188+
return false
189+
}

internal/module/module_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ func TestParseModuleConfig(t *testing.T) {
4646
assert.Equal(t, "CI Platform", param.Label)
4747
})
4848

49+
t.Run("requiredCredentials are loaded", func(t *testing.T) {
50+
assert.Equal(t, []string{"aws", "circleci", "github"}, mod.RequiredCredentials)
51+
})
52+
4953
t.Run("TemplateConfig is unmarshaled", func(t *testing.T) {
5054
mod, _ = module.ParseModuleConfig(testModuleSource)
5155
assert.Equal(t, ".circleci", mod.TemplateConfig.OutputDir)

tests/test_data/modules/ci/zero-module.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ author: ""
44
icon: ""
55
thumbnail: ""
66

7+
requiredCredentials:
8+
- aws
9+
- circleci
10+
- github
11+
712
# Template variables to populate, these could be overwritten by the file spefic frontmatter variables
813
template:
914
# strictMode: true # will only parse files that includes the .tmpl.* extension, otherwise it will copy file

0 commit comments

Comments
 (0)