github.com/saucelabs/saucectl@v0.175.1/internal/cmd/ini/common.go (about) 1 package ini 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "regexp" 8 "sort" 9 "strconv" 10 "strings" 11 12 "github.com/rs/zerolog/log" 13 "github.com/saucelabs/saucectl/internal/cypress" 14 "github.com/saucelabs/saucectl/internal/espresso" 15 "github.com/saucelabs/saucectl/internal/xcuitest" 16 17 "github.com/AlecAivazis/survey/v2" 18 "github.com/fatih/color" 19 "gopkg.in/yaml.v2" 20 ) 21 22 var configurators = map[string]func(cfg *initConfig) interface{}{ 23 "cypress": configureCypress, 24 "espresso": configureEspresso, 25 "playwright": configurePlaywright, 26 "testcafe": configureTestcafe, 27 "xcuitest": configureXCUITest, 28 "imagerunner": configureImageRunner, 29 } 30 31 var extraInfoDisplay = map[string]func(){ 32 "imagerunner": displayExtraInfoImageRunner, 33 } 34 35 var sauceignores = map[string]string{ 36 "cypress": sauceignoreCypress, 37 "playwright": sauceignorePlaywright, 38 "testcafe": sauceignoreTestcafe, 39 } 40 41 func saveConfigurationFiles(initCfg *initConfig) ([]string, error) { 42 var files []string 43 44 configFormatter, ok := configurators[initCfg.frameworkName] 45 if ok { 46 err := saveSauceConfig(configFormatter(initCfg)) 47 if err != nil { 48 return []string{}, err 49 } 50 files = append(files, ".sauce/config.yml") 51 } 52 53 sauceignore, ok := sauceignores[initCfg.frameworkName] 54 if ok { 55 err := saveSauceIgnore(sauceignore) 56 if err != nil { 57 return []string{}, err 58 } 59 files = append(files, ".sauceignore") 60 } 61 return files, nil 62 } 63 64 func saveSauceConfig(p interface{}) error { 65 fi, err := os.Stat(".sauce") 66 if err != nil && os.IsNotExist(err) { 67 if err = os.Mkdir(".sauce", 0750); err != nil { 68 return err 69 } 70 fi, err = os.Stat(".sauce") 71 if err != nil { 72 return err 73 } 74 } 75 if !fi.IsDir() { 76 return fmt.Errorf(".sauce exists and is not a directory") 77 } 78 fd, err := os.Create(".sauce/config.yml") 79 if err != nil { 80 return err 81 } 82 defer fd.Close() 83 return yaml.NewEncoder(fd).Encode(p) 84 } 85 86 func saveSauceIgnore(content string) error { 87 fd, err := os.Create(".sauceignore") 88 if err != nil { 89 return err 90 } 91 defer fd.Close() 92 _, err = fd.WriteString(content) 93 return err 94 } 95 96 func displaySummary(files []string) { 97 fmt.Println() 98 color.HiGreen("The following files have been created:") 99 for _, f := range files { 100 color.Green(" %s", f) 101 } 102 fmt.Println() 103 } 104 105 func displayExtraInfo(framework string) { 106 fn, present := extraInfoDisplay[framework] 107 if !present { 108 return 109 } 110 fn() 111 } 112 113 func completeBasic(toComplete string) []string { 114 files, _ := filepath.Glob(fmt.Sprintf("%s%s", toComplete, "*")) 115 return files 116 } 117 118 func frameworkExtValidator(framework, frameworkVersion string) survey.Validator { 119 var exts []string 120 switch framework { 121 case espresso.Kind: 122 exts = []string{".apk", ".aab"} 123 case xcuitest.Kind: 124 exts = []string{".ipa", ".app"} 125 case cypress.Kind: 126 exts = []string{".js", ".ts", ".mjs", ".cjs"} 127 if getMajorVersion(frameworkVersion) < 10 { 128 exts = []string{".json"} 129 } 130 } 131 132 return extValidator(exts) 133 } 134 135 func extValidator(validExts []string) survey.Validator { 136 return func(s interface{}) error { 137 val := s.(string) 138 found := false 139 for _, ext := range validExts { 140 if strings.HasSuffix(val, ext) { 141 found = true 142 } 143 } 144 if !found { 145 return fmt.Errorf("invalid extension. must be one of the following: %s", strings.Join(validExts, ", ")) 146 } 147 _, err := os.Stat(val) 148 if err != nil { 149 return fmt.Errorf("%s: %v", val, err) 150 } 151 return nil 152 } 153 } 154 155 func dockerImageValidator() survey.Validator { 156 re := regexp.MustCompile(`^([\w.\-_]+((:\d+|)(/[a-z0-9._-]+/[a-z0-9._-]+))|)(/|)([a-z0-9.\-_]+(/[a-z0-9.\-_]+|))(:([\w.\-_]{1,127})|)$`) 157 return func(s interface{}) error { 158 str := s.(string) 159 if re.MatchString(str) { 160 return nil 161 } 162 return fmt.Errorf("%s is not a valid docker image", str) 163 } 164 } 165 166 func getMajorVersion(frameworkVersion string) int { 167 version := strings.Split(frameworkVersion, ".")[0] 168 v, err := strconv.Atoi(version) 169 if err != nil { 170 log.Err(err).Msg("failed to get framework version.") 171 return 0 172 } 173 return v 174 } 175 176 func sortVersions(versions []string) { 177 sort.Slice(versions, func(i, j int) bool { 178 v1 := strings.Split(versions[i], ".") 179 v2 := strings.Split(versions[j], ".") 180 v1Major, _ := strconv.Atoi(v1[0]) 181 v2Major, _ := strconv.Atoi(v2[0]) 182 183 if v1Major == v2Major && len(v1) > 1 && len(v2) > 1 { 184 return strings.Compare(v1[1], v2[1]) == 1 185 } 186 return v1Major > v2Major 187 }) 188 } 189 190 func sliceContainsString(slice []string, val string) bool { 191 for _, value := range slice { 192 if value == val { 193 return true 194 } 195 } 196 return false 197 }