github.com/jfrog/jfrog-cli-core/v2@v2.51.0/common/project/projectconfig.go (about)

     1  package project
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"reflect"
     9  
    10  	"github.com/jfrog/jfrog-cli-core/v2/utils/config"
    11  	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
    12  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    13  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    14  	"github.com/jfrog/jfrog-client-go/utils/log"
    15  	"github.com/spf13/viper"
    16  )
    17  
    18  const (
    19  	ProjectConfigResolverPrefix = "resolver"
    20  	ProjectConfigDeployerPrefix = "deployer"
    21  	ProjectConfigRepo           = "repo"
    22  	ProjectConfigReleaseRepo    = "releaseRepo"
    23  	ProjectConfigServerId       = "serverId"
    24  )
    25  
    26  type ProjectType int
    27  
    28  const (
    29  	Go ProjectType = iota
    30  	Pip
    31  	Pipenv
    32  	Poetry
    33  	Npm
    34  	Pnpm
    35  	Yarn
    36  	Nuget
    37  	Maven
    38  	Gradle
    39  	Dotnet
    40  	Build
    41  	Terraform
    42  )
    43  
    44  type ConfigType string
    45  
    46  const (
    47  	YAML       ConfigType = "yaml"
    48  	PROPERTIES ConfigType = "properties"
    49  )
    50  
    51  var ProjectTypes = []string{
    52  	"go",
    53  	"pip",
    54  	"pipenv",
    55  	"poetry",
    56  	"npm",
    57  	"pnpm",
    58  	"yarn",
    59  	"nuget",
    60  	"maven",
    61  	"gradle",
    62  	"dotnet",
    63  	"build",
    64  	"terraform",
    65  }
    66  
    67  func (projectType ProjectType) String() string {
    68  	return ProjectTypes[projectType]
    69  }
    70  
    71  type MissingResolverErr struct {
    72  	message string
    73  }
    74  
    75  func (mre *MissingResolverErr) Error() string {
    76  	return mre.message
    77  }
    78  
    79  type Repository struct {
    80  	Repo             string `yaml:"repo,omitempty"`
    81  	ServerId         string `yaml:"serverId,omitempty"`
    82  	SnapshotRepo     string `yaml:"snapshotRepo,omitempty"`
    83  	ReleaseRepo      string `yaml:"releaseRepo,omitempty"`
    84  	DeployMavenDesc  bool   `yaml:"deployMavenDescriptors,omitempty"`
    85  	DeployIvyDesc    bool   `yaml:"deployIvyDescriptors,omitempty"`
    86  	IvyPattern       string `yaml:"ivyPattern,omitempty"`
    87  	ArtifactsPattern string `yaml:"artifactPattern,omitempty"`
    88  	NugetV2          bool   `yaml:"nugetV2,omitempty"`
    89  	IncludePatterns  string `yaml:"includePatterns,omitempty"`
    90  	ExcludePatterns  string `yaml:"excludePatterns,omitempty"`
    91  }
    92  
    93  type RepositoryConfig struct {
    94  	targetRepo    string
    95  	serverDetails *config.ServerDetails
    96  }
    97  
    98  // If configuration file exists in the working dir or in one of its parent dirs return its path,
    99  // otherwise return the global configuration file path
   100  func GetProjectConfFilePath(projectType ProjectType) (confFilePath string, exists bool, err error) {
   101  	confFileName := filepath.Join("projects", projectType.String()+".yaml")
   102  	projectDir, exists, err := fileutils.FindUpstream(".jfrog", fileutils.Dir)
   103  	if err != nil {
   104  		return
   105  	}
   106  	if exists {
   107  		filePath := filepath.Join(projectDir, ".jfrog", confFileName)
   108  		exists, err = fileutils.IsFileExists(filePath, false)
   109  		if err != nil {
   110  			return
   111  		}
   112  
   113  		if exists {
   114  			confFilePath = filePath
   115  			return
   116  		}
   117  	}
   118  	// If missing in the root project, check in the home dir
   119  	jfrogHomeDir, err := coreutils.GetJfrogHomeDir()
   120  	if err != nil {
   121  		return
   122  	}
   123  	filePath := filepath.Join(jfrogHomeDir, confFileName)
   124  	exists, err = fileutils.IsFileExists(filePath, false)
   125  	if exists {
   126  		confFilePath = filePath
   127  	}
   128  	return
   129  }
   130  
   131  func GetRepoConfigByPrefix(configFilePath, prefix string, vConfig *viper.Viper) (repoConfig *RepositoryConfig, err error) {
   132  	defer func() {
   133  		if err != nil {
   134  			err = errors.Join(err, fmt.Errorf("please run 'jf %s-config' with your %s repository information", vConfig.GetString("type"), prefix))
   135  		}
   136  	}()
   137  	if !vConfig.IsSet(prefix) {
   138  		err = &MissingResolverErr{fmt.Sprintf("the %s repository is missing from the config file (%s)", prefix, configFilePath)}
   139  		return
   140  	}
   141  	log.Debug(fmt.Sprintf("Found %s in the config file %s", prefix, configFilePath))
   142  	repo := vConfig.GetString(prefix + "." + ProjectConfigRepo)
   143  	if repo == "" {
   144  		// In the maven.yaml config, there's a resolver repository field named "releaseRepo"
   145  		if repo = vConfig.GetString(prefix + "." + ProjectConfigReleaseRepo); repo == "" {
   146  			err = errorutils.CheckErrorf("missing repository for %s within %s", prefix, configFilePath)
   147  			return
   148  		}
   149  	}
   150  	serverId := vConfig.GetString(prefix + "." + ProjectConfigServerId)
   151  	if serverId == "" {
   152  		err = errorutils.CheckErrorf("missing server ID for %s within %s", prefix, configFilePath)
   153  		return
   154  	}
   155  	rtDetails, err := config.GetSpecificConfig(serverId, false, true)
   156  	if err != nil {
   157  		return
   158  	}
   159  	repoConfig = &RepositoryConfig{targetRepo: repo, serverDetails: rtDetails}
   160  	return
   161  }
   162  
   163  func (repo *RepositoryConfig) IsServerDetailsEmpty() bool {
   164  	if repo.serverDetails != nil && reflect.DeepEqual(config.ServerDetails{}, repo.serverDetails) {
   165  		return false
   166  	}
   167  	return true
   168  }
   169  
   170  func (repo *RepositoryConfig) SetTargetRepo(targetRepo string) *RepositoryConfig {
   171  	repo.targetRepo = targetRepo
   172  	return repo
   173  }
   174  
   175  func (repo *RepositoryConfig) TargetRepo() string {
   176  	return repo.targetRepo
   177  }
   178  
   179  func (repo *RepositoryConfig) SetServerDetails(rtDetails *config.ServerDetails) *RepositoryConfig {
   180  	repo.serverDetails = rtDetails
   181  	return repo
   182  }
   183  
   184  func (repo *RepositoryConfig) ServerDetails() (*config.ServerDetails, error) {
   185  	return repo.serverDetails, nil
   186  }
   187  
   188  func GetResolutionOnlyConfiguration(projectType ProjectType) (*RepositoryConfig, error) {
   189  	// Get configuration file path.
   190  	confFilePath, exists, err := GetProjectConfFilePath(projectType)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	if !exists {
   195  		return nil, errorutils.CheckErrorf(projectType.String() + " Project configuration does not exist.")
   196  	}
   197  	return ReadResolutionOnlyConfiguration(confFilePath)
   198  }
   199  
   200  func ReadConfigFile(configPath string, configType ConfigType) (config *viper.Viper, err error) {
   201  	config = viper.New()
   202  	config.SetConfigType(string(configType))
   203  
   204  	f, err := os.Open(configPath)
   205  	if err != nil {
   206  		return config, errorutils.CheckError(err)
   207  	}
   208  	defer func() {
   209  		err = errorutils.CheckError(f.Close())
   210  	}()
   211  	err = config.ReadConfig(f)
   212  	return config, errorutils.CheckError(err)
   213  }
   214  
   215  func ReadResolutionOnlyConfiguration(confFilePath string) (*RepositoryConfig, error) {
   216  	log.Debug("Preparing to read the config file", confFilePath)
   217  	vConfig, err := ReadConfigFile(confFilePath, YAML)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  	return GetRepoConfigByPrefix(confFilePath, ProjectConfigResolverPrefix, vConfig)
   222  }