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  }