Skip to content

Commit 650b6a1

Browse files
Mauricio FerrariVidya2606davidgamero
authored
Create workflow from draft config (#327)
Co-authored-by: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com> Co-authored-by: David Gamero <david340804@gmail.com>
1 parent 0402605 commit 650b6a1

29 files changed

+1048
-579
lines changed

.github/workflows/integration-linux.yml

Lines changed: 36 additions & 36 deletions
Large diffs are not rendered by default.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ COPY . ./
2020
RUN make go-generate
2121

2222
RUN go mod download
23-
ENTRYPOINT ["go"]
23+
ENTRYPOINT ["go"]

cmd/create.go

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"os"
88
"strings"
99

10-
"golang.org/x/exp/maps"
1110
"gopkg.in/yaml.v3"
1211

1312
"github.com/Azure/draft/pkg/reporeader"
@@ -41,7 +40,6 @@ const emptyDefaultFlagValue = ""
4140
const currentDirDefaultFlagValue = "."
4241

4342
type createCmd struct {
44-
appName string
4543
lang string
4644
dest string
4745
deployType string
@@ -79,14 +77,13 @@ func newCreateCmd() *cobra.Command {
7977
f := cmd.Flags()
8078

8179
f.StringVarP(&cc.createConfigPath, "create-config", "c", emptyDefaultFlagValue, "specify the path to the configuration file")
82-
f.StringVarP(&cc.appName, "app", "a", emptyDefaultFlagValue, "specify the name of the helm release")
8380
f.StringVarP(&cc.lang, "language", "l", emptyDefaultFlagValue, "specify the language used to create the Kubernetes deployment")
8481
f.StringVarP(&cc.dest, "destination", "d", currentDirDefaultFlagValue, "specify the path to the project directory")
85-
f.StringVarP(&cc.deployType, "deploy-type", "", emptyDefaultFlagValue, "specify deployement type (eg. helm, kustomize, manifests)")
82+
f.StringVarP(&cc.deployType, "deploy-type", "", emptyDefaultFlagValue, "specify deployment type (eg. helm, kustomize, manifests)")
8683
f.BoolVar(&cc.dockerfileOnly, "dockerfile-only", false, "only create Dockerfile in the project directory")
8784
f.BoolVar(&cc.deploymentOnly, "deployment-only", false, "only create deployment files in the project directory")
8885
f.BoolVar(&cc.skipFileDetection, "skip-file-detection", false, "skip file detection step")
89-
f.StringArrayVarP(&cc.flagVariables, "variable", "", []string{}, "pass additional variables using repeated --variable flag")
86+
f.StringArrayVarP(&cc.flagVariables, "variable", "", []string{}, "pass template variables (e.g. --variable PORT=8080 --variable APPNAME=test)")
9087

9188
return cmd
9289
}
@@ -116,14 +113,7 @@ func (cc *createCmd) initConfig() error {
116113
func (cc *createCmd) run() error {
117114
log.Debugf("config: %s", cc.createConfigPath)
118115

119-
for _, flagVar := range cc.flagVariables {
120-
flagVarName, flagVarValue, ok := strings.Cut(flagVar, "=")
121-
if !ok {
122-
return fmt.Errorf("invalid variable format: %s", flagVar)
123-
}
124-
flagVariablesMap[flagVarName] = flagVarValue
125-
log.Debugf("flag variable %s=%s", flagVarName, flagVarValue)
126-
}
116+
flagVariablesMap = flagVariablesToMap(cc.flagVariables)
127117

128118
var dryRunRecorder *dryrunpkg.DryRunRecorder
129119
if dryRun {
@@ -276,7 +266,7 @@ func (cc *createCmd) generateDockerfile(langConfig *config.DraftConfig, lowerLan
276266
}
277267
}
278268
if !variableExists {
279-
langConfig.Variables = append(langConfig.Variables, config.BuilderVar{
269+
langConfig.Variables = append(langConfig.Variables, &config.BuilderVar{
280270
Name: k,
281271
Default: config.BuilderVarDefault{
282272
Value: v,
@@ -285,56 +275,53 @@ func (cc *createCmd) generateDockerfile(langConfig *config.DraftConfig, lowerLan
285275
}
286276
}
287277

288-
var inputs map[string]string
289278
if cc.createConfig.LanguageVariables == nil {
290-
inputs, err = prompts.RunPromptsFromConfigWithSkips(langConfig, maps.Keys(flagVariablesMap))
291-
if err != nil {
279+
langConfig.VariableMapToDraftConfig(flagVariablesMap)
280+
281+
if err = prompts.RunPromptsFromConfigWithSkips(langConfig); err != nil {
292282
return err
293283
}
294284
} else {
295-
inputs, err = validateConfigInputsToPrompts(langConfig, cc.createConfig.LanguageVariables)
285+
err = validateConfigInputsToPrompts(langConfig, cc.createConfig.LanguageVariables)
296286
if err != nil {
297287
return err
298288
}
299289
}
300290

301291
if cc.templateVariableRecorder != nil {
302-
for k, v := range inputs {
303-
cc.templateVariableRecorder.Record(k, v)
292+
for _, variable := range langConfig.Variables {
293+
cc.templateVariableRecorder.Record(variable.Name, variable.Value)
304294
}
305295
}
306296

307-
maps.Copy(inputs, flagVariablesMap)
308-
309-
if err = cc.supportedLangs.CreateDockerfileForLanguage(lowerLang, inputs, cc.templateWriter); err != nil {
297+
if err = cc.supportedLangs.CreateDockerfileForLanguage(lowerLang, langConfig, cc.templateWriter); err != nil {
310298
return fmt.Errorf("there was an error when creating the Dockerfile for language %s: %w", cc.createConfig.LanguageType, err)
311299
}
312300

313301
log.Info("--> Creating Dockerfile...\n")
314-
return err
302+
return nil
315303
}
316304

317305
func (cc *createCmd) createDeployment() error {
318306
log.Info("--- Deployment File Creation ---")
319307
d := deployments.CreateDeploymentsFromEmbedFS(template.Deployments, cc.dest)
320308
var deployType string
321-
var customInputs map[string]string
309+
var deployConfig *config.DraftConfig
322310
var err error
323311

324312
if cc.createConfig.DeployType != "" {
325313
deployType = strings.ToLower(cc.createConfig.DeployType)
326-
deployConfig, err := d.GetConfig(deployType)
314+
deployConfig, err = d.GetConfig(deployType)
327315
if err != nil {
328316
return err
329317
}
330318
if deployConfig == nil {
331319
return errors.New("invalid deployment type")
332320
}
333-
customInputs, err = validateConfigInputsToPrompts(deployConfig, cc.createConfig.DeployVariables)
321+
err = validateConfigInputsToPrompts(deployConfig, cc.createConfig.DeployVariables)
334322
if err != nil {
335323
return err
336324
}
337-
338325
} else {
339326
if cc.deployType == "" {
340327
selection := &promptui.Select{
@@ -350,27 +337,28 @@ func (cc *createCmd) createDeployment() error {
350337
deployType = cc.deployType
351338
}
352339

353-
deployConfig, err := d.GetConfig(deployType)
340+
deployConfig, err = d.GetConfig(deployType)
354341
if err != nil {
355342
return err
356343
}
357-
customInputs, err = prompts.RunPromptsFromConfigWithSkips(deployConfig, maps.Keys(flagVariablesMap))
344+
345+
deployConfig.VariableMapToDraftConfig(flagVariablesMap)
346+
347+
err = prompts.RunPromptsFromConfigWithSkips(deployConfig)
358348
if err != nil {
359349
return err
360350
}
361351
}
362352

363-
maps.Copy(customInputs, flagVariablesMap)
364-
365353
if cc.templateVariableRecorder != nil {
366-
for k, v := range customInputs {
367-
cc.templateVariableRecorder.Record(k, v)
354+
for _, variable := range deployConfig.Variables {
355+
cc.templateVariableRecorder.Record(variable.Name, variable.Value)
368356
}
369357
}
370358

371359
log.Infof("--> Creating %s Kubernetes resources...\n", deployType)
372360

373-
return d.CopyDeploymentFiles(deployType, customInputs, cc.templateWriter)
361+
return d.CopyDeploymentFiles(deployType, deployConfig, cc.templateWriter)
374362
}
375363

376364
func (cc *createCmd) createFiles(detectedLang *config.DraftConfig, lowerLang string) error {
@@ -464,26 +452,11 @@ func init() {
464452
rootCmd.AddCommand(newCreateCmd())
465453
}
466454

467-
func validateConfigInputsToPrompts(draftConfig *config.DraftConfig, provided []UserInputs) (map[string]string, error) {
468-
customInputs := make(map[string]string)
469-
455+
func validateConfigInputsToPrompts(draftConfig *config.DraftConfig, provided []UserInputs) error {
470456
// set inputs to provided values
471-
for _, variable := range provided {
472-
customInputs[variable.Name] = variable.Value
473-
}
474-
475-
if err := draftConfig.ApplyDefaultVariables(customInputs); err != nil {
476-
return nil, fmt.Errorf("validate config inputs to prompts: %w", err)
457+
for _, providedVar := range provided {
458+
draftConfig.SetVariable(providedVar.Name, providedVar.Value)
477459
}
478460

479-
for _, variable := range draftConfig.Variables {
480-
value, ok := customInputs[variable.Name]
481-
if !ok {
482-
return nil, fmt.Errorf("config missing required variable: %s with description: %s", variable.Name, variable.Description)
483-
} else if value == "" {
484-
return nil, fmt.Errorf("value for variable %s is empty", variable.Name)
485-
}
486-
}
487-
488-
return customInputs, nil
461+
return nil
489462
}

cmd/create_test.go

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,32 @@ import (
2323
func TestRun(t *testing.T) {
2424
testCreateConfig := CreateConfig{LanguageVariables: []UserInputs{{Name: "PORT", Value: "8080"}}, DeployVariables: []UserInputs{{Name: "PORT", Value: "8080"}, {Name: "APPNAME", Value: "testingCreateCommand"}}}
2525
flagVariablesMap = map[string]string{"PORT": "8080", "APPNAME": "testingCreateCommand", "VERSION": "1.18", "SERVICEPORT": "8080", "NAMESPACE": "testNamespace", "IMAGENAME": "testImage", "IMAGETAG": "latest"}
26-
mockCC := createCmd{dest: "./..", createConfig: &testCreateConfig, templateWriter: &writers.LocalFSWriter{}}
26+
mockCC := createCmd{
27+
dest: "./..",
28+
createConfig: &testCreateConfig,
29+
templateWriter: &writers.LocalFSWriter{},
30+
}
2731
deployTypes := []string{"helm", "kustomize", "manifests"}
2832
oldDockerfile, _ := ioutil.ReadFile("./../Dockerfile")
2933
oldDockerignore, _ := ioutil.ReadFile("./../.dockerignore")
3034

3135
detectedLang, lowerLang, err := mockCC.mockDetectLanguage()
32-
33-
assert.False(t, detectedLang == nil)
36+
assert.NotNil(t, detectedLang)
3437
assert.False(t, lowerLang == "")
35-
assert.True(t, err == nil)
38+
assert.Nil(t, err)
3639

3740
err = mockCC.generateDockerfile(detectedLang, lowerLang)
38-
assert.True(t, err == nil)
41+
assert.Nil(t, err)
3942

4043
//when language variables are passed in --variable flag
4144
mockCC.createConfig.LanguageVariables = nil
4245
mockCC.lang = "go"
4346
detectedLang, lowerLang, err = mockCC.mockDetectLanguage()
44-
assert.False(t, detectedLang == nil)
47+
assert.NotNil(t, detectedLang)
4548
assert.False(t, lowerLang == "")
46-
assert.True(t, err == nil)
49+
assert.Nil(t, err)
4750
err = mockCC.generateDockerfile(detectedLang, lowerLang)
48-
assert.True(t, err == nil)
51+
assert.Nil(t, err)
4952

5053
//Write back old Dockerfile
5154
err = ioutil.WriteFile("./../Dockerfile", oldDockerfile, 0644)
@@ -62,13 +65,13 @@ func TestRun(t *testing.T) {
6265
//deployment variables passed through --variable flag
6366
mockCC.deployType = deployType
6467
err = mockCC.createDeployment()
65-
assert.True(t, err == nil)
68+
assert.Nil(t, err)
6669
//check if deployment files have been created
6770
err, deploymentFiles := getAllDeploymentFiles(path.Join("../template/deployments", mockCC.deployType))
6871
assert.Nil(t, err)
6972
for _, fileName := range deploymentFiles {
7073
_, err = os.Stat(fileName)
71-
assert.True(t, err == nil)
74+
assert.Nil(t, err)
7275
}
7376

7477
os.RemoveAll("./../charts")
@@ -79,13 +82,13 @@ func TestRun(t *testing.T) {
7982
//deployment variables passed through createConfig
8083
mockCC.createConfig.DeployType = deployType
8184
err = mockCC.createDeployment()
82-
assert.True(t, err == nil)
85+
assert.Nil(t, err)
8386
//check if deployment files have been created
8487
err, deploymentFiles = getAllDeploymentFiles(path.Join("../template/deployments", mockCC.createConfig.DeployType))
8588
assert.Nil(t, err)
8689
for _, fileName := range deploymentFiles {
8790
_, err = os.Stat(fileName)
88-
assert.True(t, err == nil)
91+
assert.Nil(t, err)
8992
}
9093
mockCC.createConfig.DeployType = ""
9194

@@ -107,12 +110,12 @@ func TestRunCreateDockerfileWithRepoReader(t *testing.T) {
107110
mockCC := createCmd{createConfig: &testCreateConfig, repoReader: testRepoReader, templateWriter: &writers.LocalFSWriter{}}
108111

109112
detectedLang, lowerLang, err := mockCC.mockDetectLanguage()
110-
assert.False(t, detectedLang == nil)
113+
assert.NotNil(t, detectedLang)
111114
assert.True(t, lowerLang == "python")
112115
assert.Nil(t, err)
113116

114117
err = mockCC.generateDockerfile(detectedLang, lowerLang)
115-
assert.True(t, err == nil)
118+
assert.Nil(t, err)
116119

117120
dockerFileContent, err := ioutil.ReadFile("Dockerfile")
118121
if err != nil {
@@ -137,13 +140,13 @@ func TestInitConfig(t *testing.T) {
137140
mockCC.createConfigPath = "./../test/templates/config.yaml"
138141

139142
err := mockCC.initConfig()
140-
assert.True(t, err == nil)
141-
assert.True(t, mockCC.createConfig != nil)
143+
assert.Nil(t, err)
144+
assert.NotNil(t, mockCC.createConfig)
142145
}
143146

144147
func TestValidateConfigInputsToPromptsPass(t *testing.T) {
145148
required := config.DraftConfig{
146-
Variables: []config.BuilderVar{
149+
Variables: []*config.BuilderVar{
147150
{
148151
Name: "REQUIRED_PROVIDED",
149152
},
@@ -159,14 +162,24 @@ func TestValidateConfigInputsToPromptsPass(t *testing.T) {
159162
{Name: "REQUIRED_PROVIDED", Value: "PROVIDED_VALUE"},
160163
}
161164

162-
vars, err := validateConfigInputsToPrompts(&required, provided)
163-
assert.True(t, err == nil)
164-
assert.Equal(t, vars["REQUIRED_DEFAULTED"], "DEFAULT_VALUE")
165+
err := validateConfigInputsToPrompts(&required, provided)
166+
assert.Nil(t, err)
167+
168+
err = required.ApplyDefaultVariables()
169+
assert.Nil(t, err)
170+
171+
var1, err := required.GetVariable("REQUIRED_PROVIDED")
172+
assert.Nil(t, err)
173+
assert.Equal(t, var1.Value, "PROVIDED_VALUE")
174+
175+
var2, err := required.GetVariable("REQUIRED_DEFAULTED")
176+
assert.Nil(t, err)
177+
assert.Equal(t, var2.Value, "DEFAULT_VALUE")
165178
}
166179

167180
func TestValidateConfigInputsToPromptsMissing(t *testing.T) {
168181
required := config.DraftConfig{
169-
Variables: []config.BuilderVar{
182+
Variables: []*config.BuilderVar{
170183
{
171184
Name: "REQUIRED_PROVIDED",
172185
},
@@ -179,7 +192,10 @@ func TestValidateConfigInputsToPromptsMissing(t *testing.T) {
179192
{Name: "REQUIRED_PROVIDED"},
180193
}
181194

182-
_, err := validateConfigInputsToPrompts(&required, provided)
195+
err := validateConfigInputsToPrompts(&required, provided)
196+
assert.Nil(t, err)
197+
198+
err = required.ApplyDefaultVariables()
183199
assert.NotNil(t, err)
184200
}
185201

0 commit comments

Comments
 (0)