github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/config/keys.go (about) 1 package config 2 3 import ( 4 "errors" 5 "os" 6 "path/filepath" 7 "strconv" 8 "strings" 9 10 "github.com/apex/log" 11 "github.com/mattn/go-isatty" 12 13 "github.com/fossas/fossa-cli/cmd/fossa/flags" 14 "github.com/fossas/fossa-cli/module" 15 "github.com/fossas/fossa-cli/pkg" 16 ) 17 18 /**** Mock configuration values ****/ 19 var ( 20 MockBranch string 21 ) 22 23 /**** Global configuration keys ****/ 24 25 var ( 26 filename string 27 ) 28 29 func Version() int { 30 return file.GetVersion() 31 } 32 33 // Interactive is true if the user desires interactive output. 34 func Interactive() bool { 35 return isatty.IsTerminal(os.Stderr.Fd()) && !BoolFlag(flags.NoAnsi) 36 } 37 38 // Debug is true if the user has requested debug-level logging. 39 func Debug() bool { 40 return BoolFlag(flags.Debug) 41 } 42 43 // Filepath is the configuration file path. 44 func Filepath() string { 45 return filename 46 } 47 48 /**** API configuration keys ****/ 49 50 // APIKey is user's FOSSA API key. 51 func APIKey() string { 52 return TryStrings(file.APIKey(), os.Getenv("FOSSA_API_KEY")) 53 } 54 55 // Endpoint is the desired FOSSA backend endpoint. 56 func Endpoint() string { 57 return TryStrings(StringFlag(flags.Endpoint), file.Server(), "https://app.fossa.com") 58 } 59 60 /**** Project configuration keys ****/ 61 62 func Title() string { 63 dir, _ := os.Getwd() 64 return TryStrings(StringFlag(flags.Title), file.Title(), Project(), filepath.Base(dir)) 65 } 66 67 func Fetcher() string { 68 return TryStrings(StringFlag(flags.Fetcher), file.Fetcher(), "custom") 69 } 70 71 func Project() string { 72 inferred := "" 73 if repo != nil { 74 inferred = repo.Project() 75 } 76 return TryStrings(StringFlag(flags.Project), file.Project(), inferred) 77 } 78 79 func Revision() string { 80 inferred := "" 81 if repo != nil { 82 inferred = repo.Head().RevisionID 83 } 84 return TryStrings(StringFlag(flags.Revision), file.Revision(), inferred) 85 } 86 87 func Branch() string { 88 inferred := "" 89 if repo != nil { 90 inferred = repo.Head().Branch 91 } 92 return TryStrings(MockBranch, StringFlag(flags.Branch), file.Branch(), inferred, "master") 93 } 94 95 func ProjectURL() string { 96 return TryStrings(StringFlag(flags.ProjectURL), file.ProjectURL(), "") 97 } 98 99 func JIRAProjectKey() string { 100 return TryStrings(StringFlag(flags.JIRAProjectKey), file.JIRAProjectKey(), "") 101 } 102 103 func Link() string { 104 return TryStrings(StringFlag(flags.Link), file.Link(), "") 105 } 106 107 func Team() string { 108 return TryStrings(StringFlag(flags.Team), file.Team(), "") 109 } 110 111 /**** Analysis configuration keys ****/ 112 113 func Options() (map[string]interface{}, error) { 114 opts := ctx.StringSlice(flags.Option) 115 opts = append(opts, ctx.GlobalStringSlice(flags.Option)...) 116 117 options := make(map[string]interface{}) 118 for _, option := range opts { 119 sections := strings.Split(option, ":") 120 key := sections[0] 121 value := strings.Join(sections[1:], ":") 122 log.WithFields(log.Fields{ 123 "sections": sections, 124 "key": key, 125 "value": value, 126 }).Debug("parsing options") 127 // Attempt to parse as boolean. 128 if value == "true" { 129 options[key] = true 130 continue 131 } else if value == "false" { 132 options[key] = false 133 continue 134 } else if i, err := strconv.Atoi(value); err == nil { 135 // Attempt to parse as number. 136 options[key] = i 137 } else { 138 // Treat as a string. 139 options[key] = value 140 } 141 } 142 143 return options, nil 144 } 145 146 func Modules() ([]module.Module, error) { 147 args := ctx.Args() 148 log.WithFields(log.Fields{"args": args}).Debug("parsing modules") 149 150 var modules []module.Module 151 152 // If arguments are present, prefer arguments over the configuration file. 153 if args.Present() { 154 // Validate arguments. 155 if ctx.NArg() != 1 { 156 return nil, errors.New("must specify exactly 1 module") 157 } 158 159 // Parse module. 160 arg := args.First() 161 sections := strings.Split(arg, ":") 162 typename := sections[0] 163 name := strings.Join(sections[1:], ":") 164 mtype, err := pkg.ParseType(typename) 165 if err != nil { 166 return nil, err 167 } 168 169 // Note that these parsed modules do not have any options set yet. 170 m := module.Module{ 171 Name: name, 172 Type: mtype, 173 BuildTarget: name, 174 } 175 176 log.WithField("module", m).Debug("parsed module") 177 modules = append(modules, m) 178 } else { 179 // Otherwise, get the modules from the configuration file. 180 modules = file.Modules() 181 if len(modules) == 0 { 182 return modules, errors.New("No modules provided") 183 } 184 } 185 186 // Parse options set via the command line. 187 options, err := Options() 188 if err != nil { 189 return nil, err 190 } 191 log.WithFields(log.Fields{"options": options}).Debug("parsing options") 192 193 // Set options passed via the command line on all modules. For modules where 194 // this conflicts with a configuration file option, prefer the command line 195 // option. 196 for i, m := range modules { 197 if m.Options == nil { 198 modules[i].Options = make(map[string]interface{}) 199 } 200 201 // We iterate over and copy the command-line options instead of setting the 202 // module options equal to avoid _unsetting_ module options that were set 203 // within the configuration file. 204 for key, val := range options { 205 modules[i].Options[key] = val 206 } 207 } 208 209 return modules, nil 210 }