Skip to content

Commit cf01d86

Browse files
committed
interactive
1 parent c348f2e commit cf01d86

7 files changed

Lines changed: 113 additions & 75 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Change Log
22

3+
## [0.17.5] - 2025-03-11
4+
5+
### Added
6+
7+
- [510](https://github.com/Azure/draft/pull/510) Add build context for ADO pipelines
8+
- [509](https://github.com/Azure/draft/pull/509) Add Ingress Manifest Template
9+
- [502](https://github.com/Azure/draft/pull/502) Add Auth type for Azure login in github workflow
10+
311
## [0.17.4] - 2025-02-05
412

513
### Added

cmd/create.go

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"os"
8+
"path/filepath"
89
"strings"
910

1011
"github.com/manifoldco/promptui"
@@ -184,6 +185,9 @@ func (cc *createCmd) detectLanguage() (*handlers.Template, string, error) {
184185
return nil, "", fmt.Errorf("there was an error detecting the language: %s", err)
185186
}
186187
if len(langs) == 0 {
188+
if !interactive {
189+
return nil, "", ErrNoLanguageDetected
190+
}
187191
langs, err = promptLanguageSelection(supportedLanguages)
188192
if err != nil {
189193
return nil, "", fmt.Errorf("prompting for language: %w", err)
@@ -192,7 +196,8 @@ func (cc *createCmd) detectLanguage() (*handlers.Template, string, error) {
192196
for _, lang := range langs {
193197
log.Debugf("%s:\t%f (%s)", lang.Language, lang.Percent, lang.Color)
194198
// For now let's check here for weird stuff like go module support
195-
if lang.Language == "Go" {
199+
hasGoMod = true
200+
if interactive && lang.Language == "Go" {
196201
hasGo = true
197202

198203
selection := &promptui.Select{
@@ -204,15 +209,15 @@ func (cc *createCmd) detectLanguage() (*handlers.Template, string, error) {
204209
if err != nil {
205210
return nil, "", err
206211
}
207-
208212
hasGoMod = strings.EqualFold(selectResponse, "yes")
213+
209214
}
210215

211-
if lang.Language == "Java" {
216+
if interactive && lang.Language == "Java" {
212217

213218
selection := &promptui.Select{
214219
Label: "Linguist detected Java, are you using maven or gradle?",
215-
Items: []string{"gradle", "maven", "gradlew"},
220+
Items: []string{"maven", "gradle", "gradlew"},
216221
}
217222

218223
_, selectResponse, err := selection.Run()
@@ -302,15 +307,16 @@ func (cc *createCmd) generateDockerfile(dockerfileTemplate *handlers.Template, l
302307
}
303308
}
304309

305-
if cc.createConfig.LanguageVariables == nil {
306-
dockerfileTemplate.Config.VariableMapToDraftConfig(flagVariablesMap)
307-
308-
if err = prompts.RunPromptsFromConfigWithSkips(dockerfileTemplate.Config); err != nil {
310+
if cc.createConfig.LanguageVariables != nil || !interactive {
311+
dockerfileTemplate.Config.ApplyDefaultVariables()
312+
err = validateConfigInputsToPrompts(dockerfileTemplate.Config, cc.createConfig.LanguageVariables)
313+
if err != nil {
309314
return err
310315
}
311316
} else {
312-
err = validateConfigInputsToPrompts(dockerfileTemplate.Config, cc.createConfig.LanguageVariables)
313-
if err != nil {
317+
dockerfileTemplate.Config.VariableMapToDraftConfig(flagVariablesMap)
318+
319+
if err = prompts.RunPromptsFromConfigWithSkips(dockerfileTemplate.Config); err != nil {
314320
return err
315321
}
316322
}
@@ -329,13 +335,20 @@ func (cc *createCmd) generateDockerfile(dockerfileTemplate *handlers.Template, l
329335
return nil
330336
}
331337

332-
func (cc *createCmd) createDeployment() error {
338+
func (cc *createCmd) generateDeployment() error {
333339
log.Info("--- Deployment File Creation ---")
334340
var deployType string
335341
var deployTemplate *handlers.Template
336342
var err error
337343

344+
if !interactive {
345+
if cc.createConfig.DeployType == "" {
346+
cc.createConfig.DeployType = "manifests"
347+
log.Debugf("using default deployment type %s", cc.createConfig.DeployType)
348+
}
349+
}
338350
if cc.createConfig.DeployType != "" {
351+
339352
deployType = strings.ToLower(cc.createConfig.DeployType)
340353
deployTemplate, err = handlers.GetTemplate(fmt.Sprintf("deployment-%s", deployType), "", cc.dest, cc.templateWriter)
341354
if err != nil {
@@ -344,6 +357,28 @@ func (cc *createCmd) createDeployment() error {
344357
if deployTemplate == nil || deployTemplate.Config == nil {
345358
return errors.New("invalid deployment type")
346359
}
360+
if !interactive {
361+
currentDir, err := os.Getwd()
362+
if err != nil {
363+
return fmt.Errorf("getting current directory: %w", err)
364+
}
365+
defaultAppName := fmt.Sprintf("%s-workflow", filepath.Base(currentDir))
366+
defaultAppName, err = ToValidAppName(defaultAppName)
367+
if err != nil {
368+
log.Debugf("unable to convert default app name %q to a valid name: %v", defaultAppName, err)
369+
log.Debugf("using default app name %q", defaultAppName)
370+
defaultAppName = "my-app"
371+
}
372+
appVar, err := deployTemplate.Config.GetVariable("APPNAME")
373+
if err != nil || appVar == nil {
374+
log.Debugf("unable to get APP_NAME variable: %v", err)
375+
}
376+
if err == nil {
377+
appVar.Default.Value = defaultAppName
378+
}
379+
380+
deployTemplate.Config.ApplyDefaultVariables()
381+
}
347382
err = validateConfigInputsToPrompts(deployTemplate.Config, cc.createConfig.DeployVariables)
348383
if err != nil {
349384
return err
@@ -352,7 +387,7 @@ func (cc *createCmd) createDeployment() error {
352387
if cc.deployType == "" {
353388
selection := &promptui.Select{
354389
Label: "Select k8s Deployment Type",
355-
Items: []string{"helm", "kustomize", "manifests"},
390+
Items: []string{"manifests", "kustomize", "helm"},
356391
}
357392

358393
_, deployType, err = selection.Run()
@@ -405,7 +440,7 @@ func (cc *createCmd) createFiles(detectedLangTempalte *handlers.Template, lowerL
405440
}
406441
}
407442
if !cc.dockerfileOnly {
408-
err := cc.createDeployment()
443+
err := cc.generateDeployment()
409444
if err != nil {
410445
return err
411446
}
@@ -421,6 +456,9 @@ func (cc *createCmd) createFiles(detectedLangTempalte *handlers.Template, lowerL
421456

422457
// prompts user for dockerfile re-creation
423458
if hasDockerFile && !cc.deploymentOnly {
459+
if !interactive && !cc.skipFileDetection {
460+
return fmt.Errorf("dockerfile already exists in the directory '%s', use --skip-file-detection to overwrite", cc.dest)
461+
}
424462
selection := &promptui.Select{
425463
Label: "We found Dockerfile in the directory, would you like to recreate the Dockerfile?",
426464
Items: []string{"yes", "no"},
@@ -447,6 +485,9 @@ func (cc *createCmd) createFiles(detectedLangTempalte *handlers.Template, lowerL
447485

448486
// prompts user for deployment re-creation
449487
if hasDeploymentFiles && !cc.dockerfileOnly {
488+
if !interactive && !cc.skipFileDetection {
489+
return fmt.Errorf("deployment files already exist in the directory '%s', use --skip-file-detection to overwrite", cc.dest)
490+
}
450491
selection := &promptui.Select{
451492
Label: "We found deployment files in the directory, would you like to create new deployment files?",
452493
Items: []string{"yes", "no"},
@@ -465,7 +506,7 @@ func (cc *createCmd) createFiles(detectedLangTempalte *handlers.Template, lowerL
465506
} else if hasDeploymentFiles {
466507
log.Info("--> Found deployment directory in local directory, skipping deployment file creation...")
467508
} else if !cc.dockerfileOnly {
468-
err := cc.createDeployment()
509+
err := cc.generateDeployment()
469510
if err != nil {
470511
return err
471512
}

cmd/create_test.go

Lines changed: 45 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -20,81 +20,69 @@ import (
2020
)
2121

2222
func TestRun(t *testing.T) {
23-
testCreateConfig := CreateConfig{LanguageVariables: []UserInputs{{Name: "PORT", Value: "8080"}}, DeployVariables: []UserInputs{{Name: "PORT", Value: "8080"}, {Name: "APPNAME", Value: "testingCreateCommand"}, {Name: "DOCKERFILENAME", Value: "Dockerfile"}}}
24-
flagVariablesMap = map[string]string{"PORT": "8080", "APPNAME": "testingCreateCommand", "VERSION": "1.18", "SERVICEPORT": "8080", "NAMESPACE": "testNamespace", "IMAGENAME": "testImage", "IMAGETAG": "latest", "DOCKERFILENAME": "test.Dockerfile"}
25-
mockCC := createCmd{
26-
dest: "./..",
27-
createConfig: &testCreateConfig,
28-
templateWriter: &writers.LocalFSWriter{},
29-
}
3023
deployTypes := []string{"helm", "kustomize", "manifests"}
31-
oldDockerfile, _ := ioutil.ReadFile("./../Dockerfile")
32-
oldDockerignore, _ := ioutil.ReadFile("./../.dockerignore")
33-
34-
detectedLang, lowerLang, err := mockCC.mockDetectLanguage()
35-
assert.NotNil(t, detectedLang)
36-
assert.False(t, lowerLang == "")
37-
assert.Nil(t, err)
3824

39-
err = mockCC.generateDockerfile(detectedLang, lowerLang)
40-
assert.Nil(t, err)
25+
for _, deployType := range deployTypes {
26+
var testDir = t.TempDir()
27+
28+
testCreateConfig := CreateConfig{
29+
DeployType: deployType,
30+
LanguageVariables: []UserInputs{{Name: "PORT", Value: "8080"}},
31+
DeployVariables: []UserInputs{
32+
{Name: "PORT", Value: "8080"},
33+
{Name: "APPNAME", Value: "testingCreateCommand"},
34+
{Name: "DOCKERFILENAME", Value: "Dockerfile"},
35+
},
36+
}
37+
flagVariablesMap = map[string]string{"PORT": "8080", "APPNAME": "testingCreateCommand", "VERSION": "1.18", "SERVICEPORT": "8080", "NAMESPACE": "testNamespace", "IMAGENAME": "testImage", "IMAGETAG": "latest", "DOCKERFILENAME": "test.Dockerfile"}
38+
mockCC := createCmd{
39+
deployType: deployType,
40+
dest: testDir,
41+
createConfig: &testCreateConfig,
42+
templateWriter: &writers.LocalFSWriter{},
43+
}
4144

42-
//when language variables are passed in --variable flag
43-
mockCC.createConfig.LanguageVariables = nil
44-
mockCC.lang = "go"
45-
detectedLang, lowerLang, err = mockCC.mockDetectLanguage()
46-
assert.NotNil(t, detectedLang)
47-
assert.False(t, lowerLang == "")
48-
assert.Nil(t, err)
49-
err = mockCC.generateDockerfile(detectedLang, lowerLang)
50-
assert.Nil(t, err)
45+
err := os.WriteFile(filepath.Join(testDir, "main.go"), []byte("//placeholder"), 0644)
46+
assert.Nil(t, err)
47+
detectedLang, lowerLang, err := mockCC.mockDetectLanguage()
48+
assert.NotNil(t, detectedLang)
49+
assert.False(t, lowerLang == "")
50+
assert.Nil(t, err)
5151

52-
//Write back old Dockerfile
53-
err = ioutil.WriteFile("./../Dockerfile", oldDockerfile, 0644)
54-
if err != nil {
55-
t.Error(err)
56-
}
52+
err = mockCC.generateDockerfile(detectedLang, lowerLang)
53+
assert.Nil(t, err)
5754

58-
err = ioutil.WriteFile("./../.dockerignore", oldDockerignore, 0644)
59-
if err != nil {
60-
t.Error(err)
61-
}
55+
//when language variables are passed in --variable flag
56+
mockCC.createConfig.LanguageVariables = nil
57+
mockCC.lang = "go"
58+
detectedLang, lowerLang, err = mockCC.mockDetectLanguage()
59+
assert.NotNil(t, detectedLang)
60+
assert.False(t, lowerLang == "")
61+
assert.Nil(t, err)
62+
err = mockCC.generateDockerfile(detectedLang, lowerLang)
63+
assert.Nil(t, err)
6264

63-
for _, deployType := range deployTypes {
6465
//deployment variables passed through --variable flag
65-
mockCC.deployType = deployType
66-
err = mockCC.createDeployment()
66+
err = mockCC.generateDeployment()
6767
assert.Nil(t, err)
6868
//check if deployment files have been created
69-
err, deploymentFiles := getAllDeploymentFiles(path.Join("../template/deployments", mockCC.deployType))
69+
deploymentFiles, err := getAllDeploymentFiles(filepath.Join("../template/deployments", mockCC.deployType))
7070
assert.Nil(t, err)
7171
for _, fileName := range deploymentFiles {
72-
_, err = os.Stat(fileName)
72+
_, err = os.Stat(filepath.Join(testDir, fileName))
7373
assert.Nil(t, err)
7474
}
7575

76-
os.RemoveAll("./../charts")
77-
os.RemoveAll("./../base")
78-
os.RemoveAll("./../overlays")
79-
os.RemoveAll("./../manifests")
80-
8176
//deployment variables passed through createConfig
82-
mockCC.createConfig.DeployType = deployType
83-
err = mockCC.createDeployment()
77+
err = mockCC.generateDeployment()
8478
assert.Nil(t, err)
8579
//check if deployment files have been created
86-
err, deploymentFiles = getAllDeploymentFiles(path.Join("../template/deployments", mockCC.createConfig.DeployType))
80+
deploymentFiles, err = getAllDeploymentFiles(path.Join("../template/deployments", mockCC.createConfig.DeployType))
8781
assert.Nil(t, err)
8882
for _, fileName := range deploymentFiles {
89-
_, err = os.Stat(fileName)
83+
_, err = os.Stat(filepath.Join(testDir, fileName))
9084
assert.Nil(t, err)
9185
}
92-
mockCC.createConfig.DeployType = ""
93-
94-
os.RemoveAll("./../charts")
95-
os.RemoveAll("./../base")
96-
os.RemoveAll("./../overlays")
97-
os.RemoveAll("./../manifests")
9886
}
9987
}
10088

@@ -270,18 +258,18 @@ func TestDefaultValues(t *testing.T) {
270258
assert.Equal(t, currentDirDefaultFlagValue, ".")
271259
}
272260

273-
func getAllDeploymentFiles(src string) (error, []string) {
261+
func getAllDeploymentFiles(src string) ([]string, error) {
274262
deploymentFiles := []string{}
275263
err := filepath.Walk(src,
276264
func(path string, info os.FileInfo, err error) error {
277265
if err != nil {
278266
return err
279267
}
280-
filePath := strings.ReplaceAll(path, src, "./..")
268+
filePath := strings.ReplaceAll(path, src, "")
281269
if info.Name() != "draft.yaml" {
282270
deploymentFiles = append(deploymentFiles, filePath)
283271
}
284272
return nil
285273
})
286-
return err, deploymentFiles
274+
return deploymentFiles, err
287275
}

cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var provider string
1414
var silent bool
1515
var dryRun bool
1616
var dryRunFile string
17+
var interactive bool
1718

1819
// rootCmd represents the base command when called without any subcommands
1920
var rootCmd = &cobra.Command{
@@ -62,5 +63,6 @@ func init() {
6263
rootCmd.PersistentFlags().StringVarP(&provider, "provider", "p", "azure", "cloud provider")
6364
rootCmd.PersistentFlags().BoolVarP(&silent, "silent", "", false, "enable silent logging")
6465
rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "", false, "enable dry run mode in which no files are written to disk")
66+
rootCmd.PersistentFlags().BoolVarP(&interactive, "interactive", "", false, "toggle interactive prompting for user input (default is true, use --interactive=false to disable)")
6567
rootCmd.PersistentFlags().StringVar(&dryRunFile, "dry-run-file", "", "optional file to write dry run summary in json format into (requires --dry-run flag)")
6668
}

cmd/setupgh.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func fillSetUpConfig(sc *providers.SetUpCmd, gh providers.GhClient, az providers
9292
return fmt.Errorf("getting current directory: %w", err)
9393
}
9494
defaultAppName := fmt.Sprintf("%s-workflow", filepath.Base(currentDir))
95-
defaultAppName, err = toValidAppName(defaultAppName)
95+
defaultAppName, err = ToValidAppName(defaultAppName)
9696
if err != nil {
9797
log.Debugf("unable to convert default app name %q to a valid name: %v", defaultAppName, err)
9898
log.Debugf("using default app name %q", defaultAppName)
@@ -149,7 +149,7 @@ func fillSetUpConfig(sc *providers.SetUpCmd, gh providers.GhClient, az providers
149149
return nil
150150
}
151151

152-
func toValidAppName(name string) (string, error) {
152+
func ToValidAppName(name string) (string, error) {
153153
// replace all underscores with hyphens
154154
cleanedName := strings.ReplaceAll(name, "_", "-")
155155
// replace all spaces with hyphens

cmd/setupgh_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func TestToValidAppName(t *testing.T) {
8585

8686
for _, tc := range testCases {
8787
t.Run(tc.testCaseName, func(t *testing.T) {
88-
result, err := toValidAppName(tc.nameInput)
88+
result, err := ToValidAppName(tc.nameInput)
8989
if tc.shouldError {
9090
assert.Error(t, err)
9191
} else {

pkg/linguist/linguist.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ func Alias(lang *Language) *Language {
302302
"c#": "csharp",
303303
"go module": "gomodule",
304304
"typescript": "javascript",
305-
"xml": "javascript",
306305
}
307306

308307
if alias, ok := packAliases[strings.ToLower(lang.Language)]; ok {

0 commit comments

Comments
 (0)