github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/commands/utils/configfile.go (about) 1 package utils 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/codegangsta/cli" 11 "github.com/jfrog/jfrog-cli-core/artifactory/utils" 12 "github.com/jfrog/jfrog-cli-core/utils/config" 13 "github.com/jfrog/jfrog-cli-core/utils/coreutils" 14 "github.com/jfrog/jfrog-client-go/utils/errorutils" 15 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 16 "github.com/jfrog/jfrog-client-go/utils/log" 17 "gopkg.in/yaml.v2" 18 ) 19 20 const BUILD_CONF_VERSION = 1 21 22 const ( 23 // Common flags 24 Global = "global" 25 ResolutionServerId = "server-id-resolve" 26 DeploymentServerId = "server-id-deploy" 27 ResolutionRepo = "repo-resolve" 28 DeploymentRepo = "repo-deploy" 29 30 // Maven flags 31 ResolutionReleasesRepo = "repo-resolve-releases" 32 ResolutionSnapshotsRepo = "repo-resolve-snapshots" 33 DeploymentReleasesRepo = "repo-deploy-releases" 34 DeploymentSnapshotsRepo = "repo-deploy-snapshots" 35 36 // Gradle flags 37 UsesPlugin = "uses-plugin" 38 UseWrapper = "use-wrapper" 39 DeployMavenDesc = "deploy-maven-desc" 40 DeployIvyDesc = "deploy-ivy-desc" 41 IvyDescPattern = "ivy-desc-pattern" 42 IvyArtifactsPattern = "ivy-artifacts-pattern" 43 44 // Nuget flags 45 NugetV2 = "nuget-v2" 46 ) 47 48 type ConfigFile struct { 49 Interactive bool `yaml:"-"` 50 Version int `yaml:"version,omitempty"` 51 ConfigType string `yaml:"type,omitempty"` 52 Resolver utils.Repository `yaml:"resolver,omitempty"` 53 Deployer utils.Repository `yaml:"deployer,omitempty"` 54 UsePlugin bool `yaml:"usePlugin,omitempty"` 55 UseWrapper bool `yaml:"useWrapper,omitempty"` 56 } 57 58 func NewConfigFile(confType utils.ProjectType, c *cli.Context) *ConfigFile { 59 configFile := &ConfigFile{ 60 Version: BUILD_CONF_VERSION, 61 ConfigType: confType.String(), 62 } 63 configFile.populateConfigFromFlags(c) 64 switch confType { 65 case utils.Maven: 66 configFile.populateMavenConfigFromFlags(c) 67 case utils.Gradle: 68 configFile.populateGradleConfigFromFlags(c) 69 case utils.Nuget, utils.Dotnet: 70 configFile.populateNugetConfigFromFlags(c) 71 } 72 return configFile 73 } 74 75 func CreateBuildConfig(c *cli.Context, confType utils.ProjectType) (err error) { 76 global := c.Bool(Global) 77 projectDir, err := utils.GetProjectDir(global) 78 if err != nil { 79 return err 80 } 81 if err = fileutils.CreateDirIfNotExist(projectDir); err != nil { 82 return err 83 } 84 configFilePath := filepath.Join(projectDir, confType.String()+".yaml") 85 configFile := NewConfigFile(confType, c) 86 if err := configFile.VerifyConfigFile(configFilePath); err != nil { 87 return err 88 } 89 if configFile.Interactive { 90 switch confType { 91 case utils.Go: 92 err = configFile.configGo() 93 case utils.Pip: 94 err = configFile.configPip() 95 case utils.Npm: 96 err = configFile.configNpm() 97 case utils.Dotnet: 98 fallthrough 99 case utils.Nuget: 100 err = configFile.configDotnet() 101 case utils.Maven: 102 err = configFile.configMaven() 103 case utils.Gradle: 104 err = configFile.configGradle() 105 } 106 if err != nil { 107 return errorutils.CheckError(err) 108 } 109 } 110 if err = configFile.validateConfig(); err != nil { 111 return err 112 } 113 resBytes, err := yaml.Marshal(&configFile) 114 if err != nil { 115 return errorutils.CheckError(err) 116 } 117 if err = ioutil.WriteFile(configFilePath, resBytes, 0644); err != nil { 118 return errorutils.CheckError(err) 119 } 120 log.Info(confType.String() + " build config successfully created.") 121 return nil 122 } 123 124 func isInteractive(c *cli.Context) bool { 125 if strings.ToLower(os.Getenv(coreutils.CI)) == "true" { 126 return false 127 } 128 return !isAnyFlagSet(c, ResolutionServerId, ResolutionRepo, DeploymentServerId, DeploymentRepo) 129 } 130 131 func isAnyFlagSet(c *cli.Context, flagNames ...string) bool { 132 for _, flagName := range flagNames { 133 if c.IsSet(flagName) { 134 return true 135 } 136 } 137 return false 138 } 139 140 // Populate configuration from cli flags 141 func (configFile *ConfigFile) populateConfigFromFlags(c *cli.Context) { 142 configFile.Resolver.ServerId = c.String(ResolutionServerId) 143 configFile.Resolver.Repo = c.String(ResolutionRepo) 144 configFile.Deployer.ServerId = c.String(DeploymentServerId) 145 configFile.Deployer.Repo = c.String(DeploymentRepo) 146 configFile.Interactive = isInteractive(c) 147 } 148 149 // Populate Maven related configuration from cli flags 150 func (configFile *ConfigFile) populateMavenConfigFromFlags(c *cli.Context) { 151 configFile.Resolver.SnapshotRepo = c.String(ResolutionSnapshotsRepo) 152 configFile.Resolver.ReleaseRepo = c.String(ResolutionReleasesRepo) 153 configFile.Deployer.SnapshotRepo = c.String(DeploymentSnapshotsRepo) 154 configFile.Deployer.ReleaseRepo = c.String(DeploymentReleasesRepo) 155 configFile.Interactive = configFile.Interactive && !isAnyFlagSet(c, ResolutionSnapshotsRepo, ResolutionReleasesRepo, DeploymentSnapshotsRepo, DeploymentReleasesRepo) 156 } 157 158 // Populate Gradle related configuration from cli flags 159 func (configFile *ConfigFile) populateGradleConfigFromFlags(c *cli.Context) { 160 configFile.Deployer.DeployMavenDesc = c.BoolT(DeployMavenDesc) 161 configFile.Deployer.DeployIvyDesc = c.BoolT(DeployIvyDesc) 162 configFile.Deployer.IvyPattern = defaultIfNotSet(c, IvyDescPattern, "[organization]/[module]/ivy-[revision].xml") 163 configFile.Deployer.ArtifactsPattern = defaultIfNotSet(c, IvyArtifactsPattern, "[organization]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]") 164 configFile.UsePlugin = c.Bool(UsesPlugin) 165 configFile.UseWrapper = c.Bool(UseWrapper) 166 configFile.Interactive = configFile.Interactive && !isAnyFlagSet(c, DeployMavenDesc, DeployIvyDesc, IvyDescPattern, IvyArtifactsPattern, UsesPlugin, UseWrapper) 167 } 168 169 // Populate NuGet related configuration from cli flags 170 func (configFile *ConfigFile) populateNugetConfigFromFlags(c *cli.Context) { 171 configFile.Resolver.NugetV2 = c.Bool(NugetV2) 172 configFile.Interactive = configFile.Interactive && !isAnyFlagSet(c, NugetV2) 173 } 174 175 // Verify config file doesn't exist or prompt to override it 176 func (configFile *ConfigFile) VerifyConfigFile(configFilePath string) error { 177 exists, err := fileutils.IsFileExists(configFilePath, false) 178 if err != nil { 179 return err 180 } 181 if exists { 182 if !configFile.Interactive { 183 return nil 184 } 185 override := coreutils.AskYesNo("Configuration file already exists at "+configFilePath+". Override it?", false) 186 if !override { 187 return errorutils.CheckError(errors.New("operation canceled")) 188 } 189 return nil 190 } 191 192 // Create config file to make sure the path is valid 193 f, err := os.OpenFile(configFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 194 if errorutils.CheckError(err) != nil { 195 return err 196 } 197 f.Close() 198 // The file will be written at the end of successful configuration command. 199 return errorutils.CheckError(os.Remove(configFilePath)) 200 } 201 202 func (configFile *ConfigFile) configGo() error { 203 return configFile.setDeployerResolver() 204 } 205 206 func (configFile *ConfigFile) configPip() error { 207 return configFile.setResolver() 208 } 209 210 func (configFile *ConfigFile) configNpm() error { 211 return configFile.setDeployerResolver() 212 } 213 214 func (configFile *ConfigFile) configDotnet() error { 215 if err := configFile.setResolver(); err != nil { 216 return err 217 } 218 if configFile.Resolver.ServerId != "" { 219 configFile.setUseNugetV2() 220 } 221 return nil 222 } 223 224 func (configFile *ConfigFile) configMaven() error { 225 // Set resolution repositories 226 if err := configFile.setResolverId(); err != nil { 227 return err 228 } 229 if configFile.Resolver.ServerId != "" { 230 if err := configFile.setRepo(&configFile.Resolver.ReleaseRepo, "Set resolution repository for release dependencies", configFile.Resolver.ServerId, utils.REMOTE); err != nil { 231 return err 232 } 233 if err := configFile.setRepo(&configFile.Resolver.SnapshotRepo, "Set resolution repository for snapshot dependencies", configFile.Resolver.ServerId, utils.REMOTE); err != nil { 234 return err 235 } 236 } 237 // Set deployment repositories 238 if err := configFile.setDeployerId(); err != nil { 239 return err 240 } 241 if configFile.Deployer.ServerId != "" { 242 if err := configFile.setRepo(&configFile.Deployer.ReleaseRepo, "Set repository for release artifacts deployment", configFile.Deployer.ServerId, utils.LOCAL); err != nil { 243 return err 244 } 245 return configFile.setRepo(&configFile.Deployer.SnapshotRepo, "Set repository for snapshot artifacts deployment", configFile.Deployer.ServerId, utils.LOCAL) 246 } 247 return nil 248 } 249 250 func (configFile *ConfigFile) configGradle() error { 251 if err := configFile.setDeployerResolver(); err != nil { 252 return err 253 } 254 if configFile.Deployer.ServerId != "" { 255 configFile.setMavenIvyDescriptors() 256 } 257 configFile.readGradleGlobalConfig() 258 return nil 259 } 260 261 func (configFile *ConfigFile) readGradleGlobalConfig() { 262 configFile.UsePlugin = coreutils.AskYesNo("Is the Gradle Artifactory Plugin already applied in the build script?", false) 263 configFile.UseWrapper = coreutils.AskYesNo("Use Gradle wrapper?", false) 264 } 265 266 func (configFile *ConfigFile) setDeployer() error { 267 // Set deployer id 268 if err := configFile.setDeployerId(); err != nil { 269 return err 270 } 271 272 // Set deployment repository 273 if configFile.Deployer.ServerId != "" { 274 return configFile.setRepo(&configFile.Deployer.Repo, "Set repository for artifacts deployment", configFile.Deployer.ServerId, utils.LOCAL) 275 } 276 return nil 277 } 278 279 func (configFile *ConfigFile) setResolver() error { 280 // Set resolver id 281 if err := configFile.setResolverId(); err != nil { 282 return err 283 } 284 // Set resolution repository 285 if configFile.Resolver.ServerId != "" { 286 return configFile.setRepo(&configFile.Resolver.Repo, "Set repository for dependencies resolution", configFile.Resolver.ServerId, utils.REMOTE) 287 } 288 return nil 289 } 290 291 func (configFile *ConfigFile) setDeployerResolver() error { 292 if err := configFile.setResolver(); err != nil { 293 return err 294 } 295 return configFile.setDeployer() 296 } 297 298 func (configFile *ConfigFile) setResolverId() error { 299 return configFile.setServerId(&configFile.Resolver.ServerId, "Resolve dependencies from Artifactory?") 300 } 301 302 func (configFile *ConfigFile) setDeployerId() error { 303 return configFile.setServerId(&configFile.Deployer.ServerId, "Deploy project artifacts to Artifactory?") 304 } 305 306 func (configFile *ConfigFile) setServerId(serverId *string, useArtifactoryQuestion string) error { 307 var err error 308 *serverId, err = readArtifactoryServer(useArtifactoryQuestion) 309 return err 310 } 311 312 func (configFile *ConfigFile) setRepo(repo *string, message string, serverId string, repoType utils.RepoType) error { 313 var err error 314 if *repo == "" { 315 *repo, err = readRepo(message+PressTabMsg, serverId, repoType, utils.VIRTUAL) 316 } 317 return err 318 } 319 320 func (configFile *ConfigFile) setMavenIvyDescriptors() { 321 configFile.Deployer.DeployMavenDesc = coreutils.AskYesNo("Deploy Maven descriptors?", false) 322 configFile.Deployer.DeployIvyDesc = coreutils.AskYesNo("Deploy Ivy descriptors?", false) 323 324 if configFile.Deployer.DeployIvyDesc { 325 configFile.Deployer.IvyPattern = AskStringWithDefault("", "Set Ivy descriptor pattern", "[organization]/[module]/ivy-[revision].xml") 326 configFile.Deployer.ArtifactsPattern = AskStringWithDefault("", "Set Ivy artifact pattern", "[organization]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]") 327 } 328 } 329 330 func (configFile *ConfigFile) setUseNugetV2() { 331 configFile.Resolver.NugetV2 = coreutils.AskYesNo("Use NuGet V2 Protocol?", false) 332 } 333 334 // Check correctness of spec file configuration 335 func (configFile *ConfigFile) validateConfig() error { 336 resolver := configFile.Resolver 337 releaseRepo := resolver.ReleaseRepo 338 snapshotRepo := resolver.SnapshotRepo 339 if resolver.ServerId != "" { 340 if resolver.Repo == "" && releaseRepo == "" && snapshotRepo == "" { 341 return errorutils.CheckError(errors.New("Resolution repository/ies must be set.")) 342 } 343 if (releaseRepo == "" && snapshotRepo != "") || (releaseRepo != "" && snapshotRepo == "") { 344 return errorutils.CheckError(errors.New("Resolution snapshot and release repositories must be set.")) 345 } 346 } else { 347 if resolver.Repo != "" || releaseRepo != "" || snapshotRepo != "" { 348 return errorutils.CheckError(errors.New("Resolver server ID must be set.")) 349 } 350 } 351 deployer := configFile.Deployer 352 releaseRepo = deployer.ReleaseRepo 353 snapshotRepo = deployer.SnapshotRepo 354 if deployer.ServerId != "" { 355 if deployer.Repo == "" && releaseRepo == "" && snapshotRepo == "" { 356 return errorutils.CheckError(errors.New("Deployment repository/ies must be set.")) 357 } 358 if (releaseRepo == "" && snapshotRepo != "") || (releaseRepo != "" && snapshotRepo == "") { 359 return errorutils.CheckError(errors.New("Deployment snapshot and release repositories must be set.")) 360 } 361 } else { 362 if deployer.Repo != "" || releaseRepo != "" || snapshotRepo != "" { 363 return errorutils.CheckError(errors.New("Deployer server ID must be set.")) 364 } 365 } 366 return nil 367 } 368 369 // Get Artifactory serverId from the user. If useArtifactoryQuestion is not empty, ask first whether to use artifactory. 370 func readArtifactoryServer(useArtifactoryQuestion string) (string, error) { 371 // Get all Artifactory servers 372 serversIds, defaultServer, err := getServersIdAndDefault() 373 if err != nil { 374 return "", err 375 } 376 if len(serversIds) == 0 { 377 return "", errorutils.CheckError(errors.New("no Artifactory servers configured. Use the 'jfrog rt c' command to set the Artifactory server details")) 378 } 379 380 // Ask whether to use artifactory 381 if useArtifactoryQuestion != "" { 382 useArtifactory := coreutils.AskYesNo(useArtifactoryQuestion, true) 383 if !useArtifactory { 384 return "", nil 385 } 386 } 387 388 return AskFromList("", "Set Artifactory server ID", false, ConvertToSuggests(serversIds), defaultServer), nil 389 } 390 391 func readRepo(promptPrefix string, serverId string, repoTypes ...utils.RepoType) (string, error) { 392 availableRepos, err := getRepositories(serverId, repoTypes...) 393 if err != nil { 394 log.Error("failed getting repositories list: " + err.Error()) 395 // Continue without auto complete. 396 availableRepos = []string{} 397 } 398 if len(availableRepos) > 0 { 399 return AskFromListWithMismatchConfirmation(promptPrefix, "Repository not found.", ConvertToSuggests(availableRepos)), nil 400 } 401 return AskString("", promptPrefix, false, false), nil 402 } 403 404 func getServersIdAndDefault() ([]string, string, error) { 405 allConfigs, err := config.GetAllArtifactoryConfigs() 406 if err != nil { 407 return nil, "", err 408 } 409 var defaultVal string 410 var serversId []string 411 for _, v := range allConfigs { 412 if v.IsDefault { 413 defaultVal = v.ServerId 414 } 415 serversId = append(serversId, v.ServerId) 416 } 417 return serversId, defaultVal, nil 418 } 419 420 func getRepositories(serverId string, repoTypes ...utils.RepoType) ([]string, error) { 421 artDetails, err := config.GetArtifactorySpecificConfig(serverId, false, true) 422 if err != nil { 423 return nil, err 424 } 425 426 artAuth, err := artDetails.CreateArtAuthConfig() 427 if err != nil { 428 return nil, err 429 } 430 431 return utils.GetRepositories(artAuth, repoTypes...) 432 } 433 434 func defaultIfNotSet(c *cli.Context, flagName string, defaultValue string) string { 435 if c.IsSet(flagName) { 436 return c.String(flagName) 437 } 438 return defaultValue 439 }