github.com/jfrog/jfrog-cli-core/v2@v2.51.0/lifecycle/createcommon.go (about)

     1  package lifecycle
     2  
     3  import (
     4  	"github.com/jfrog/jfrog-cli-core/v2/common/spec"
     5  	"github.com/jfrog/jfrog-cli-core/v2/utils/config"
     6  	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
     7  	"github.com/jfrog/jfrog-client-go/lifecycle/services"
     8  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
     9  )
    10  
    11  const (
    12  	missingCreationSourcesErrMsg  = "unexpected err while validating spec - could not detect any creation sources"
    13  	multipleCreationSourcesErrMsg = "multiple creation sources were detected in separate spec files. Only a single creation source should be provided. Detected:"
    14  	singleAqlErrMsg               = "only a single aql query can be provided"
    15  )
    16  
    17  type ReleaseBundleCreateCommand struct {
    18  	releaseBundleCmd
    19  	signingKeyName string
    20  	spec           *spec.SpecFiles
    21  	// Backward compatibility:
    22  	buildsSpecPath         string
    23  	releaseBundlesSpecPath string
    24  }
    25  
    26  func NewReleaseBundleCreateCommand() *ReleaseBundleCreateCommand {
    27  	return &ReleaseBundleCreateCommand{}
    28  }
    29  
    30  func (rbc *ReleaseBundleCreateCommand) SetServerDetails(serverDetails *config.ServerDetails) *ReleaseBundleCreateCommand {
    31  	rbc.serverDetails = serverDetails
    32  	return rbc
    33  }
    34  
    35  func (rbc *ReleaseBundleCreateCommand) SetReleaseBundleName(releaseBundleName string) *ReleaseBundleCreateCommand {
    36  	rbc.releaseBundleName = releaseBundleName
    37  	return rbc
    38  }
    39  
    40  func (rbc *ReleaseBundleCreateCommand) SetReleaseBundleVersion(releaseBundleVersion string) *ReleaseBundleCreateCommand {
    41  	rbc.releaseBundleVersion = releaseBundleVersion
    42  	return rbc
    43  }
    44  
    45  func (rbc *ReleaseBundleCreateCommand) SetSigningKeyName(signingKeyName string) *ReleaseBundleCreateCommand {
    46  	rbc.signingKeyName = signingKeyName
    47  	return rbc
    48  }
    49  
    50  func (rbc *ReleaseBundleCreateCommand) SetSync(sync bool) *ReleaseBundleCreateCommand {
    51  	rbc.sync = sync
    52  	return rbc
    53  }
    54  
    55  func (rbc *ReleaseBundleCreateCommand) SetReleaseBundleProject(rbProjectKey string) *ReleaseBundleCreateCommand {
    56  	rbc.rbProjectKey = rbProjectKey
    57  	return rbc
    58  }
    59  
    60  func (rbc *ReleaseBundleCreateCommand) SetSpec(spec *spec.SpecFiles) *ReleaseBundleCreateCommand {
    61  	rbc.spec = spec
    62  	return rbc
    63  }
    64  
    65  // Deprecated
    66  func (rbc *ReleaseBundleCreateCommand) SetBuildsSpecPath(buildsSpecPath string) *ReleaseBundleCreateCommand {
    67  	rbc.buildsSpecPath = buildsSpecPath
    68  	return rbc
    69  }
    70  
    71  // Deprecated
    72  func (rbc *ReleaseBundleCreateCommand) SetReleaseBundlesSpecPath(releaseBundlesSpecPath string) *ReleaseBundleCreateCommand {
    73  	rbc.releaseBundlesSpecPath = releaseBundlesSpecPath
    74  	return rbc
    75  }
    76  
    77  func (rbc *ReleaseBundleCreateCommand) CommandName() string {
    78  	return "rb_create"
    79  }
    80  
    81  func (rbc *ReleaseBundleCreateCommand) ServerDetails() (*config.ServerDetails, error) {
    82  	return rbc.serverDetails, nil
    83  }
    84  
    85  func (rbc *ReleaseBundleCreateCommand) Run() error {
    86  	if err := validateArtifactoryVersionSupported(rbc.serverDetails); err != nil {
    87  		return err
    88  	}
    89  
    90  	servicesManager, rbDetails, queryParams, err := rbc.getPrerequisites()
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	sourceType, err := rbc.identifySourceType()
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	switch sourceType {
   101  	case services.Aql:
   102  		return rbc.createFromAql(servicesManager, rbDetails, queryParams)
   103  	case services.Artifacts:
   104  		return rbc.createFromArtifacts(servicesManager, rbDetails, queryParams)
   105  	case services.Builds:
   106  		return rbc.createFromBuilds(servicesManager, rbDetails, queryParams)
   107  	case services.ReleaseBundles:
   108  		return rbc.createFromReleaseBundles(servicesManager, rbDetails, queryParams)
   109  	default:
   110  		return errorutils.CheckErrorf("unknown source for release bundle creation was provided")
   111  	}
   112  }
   113  
   114  func (rbc *ReleaseBundleCreateCommand) identifySourceType() (services.SourceType, error) {
   115  	switch {
   116  	case rbc.buildsSpecPath != "":
   117  		return services.Builds, nil
   118  	case rbc.releaseBundlesSpecPath != "":
   119  		return services.ReleaseBundles, nil
   120  	case rbc.spec != nil:
   121  		return validateAndIdentifyRbCreationSpec(rbc.spec.Files)
   122  	default:
   123  		return "", errorutils.CheckErrorf("a spec file input is mandatory")
   124  	}
   125  }
   126  
   127  func validateAndIdentifyRbCreationSpec(files []spec.File) (services.SourceType, error) {
   128  	if len(files) == 0 {
   129  		return "", errorutils.CheckErrorf("spec must include at least one file group")
   130  	}
   131  
   132  	var detectedCreationSources []services.SourceType
   133  	for _, file := range files {
   134  		sourceType, err := validateFile(file)
   135  		if err != nil {
   136  			return "", err
   137  		}
   138  		detectedCreationSources = append(detectedCreationSources, sourceType)
   139  	}
   140  
   141  	if err := validateCreationSources(detectedCreationSources); err != nil {
   142  		return "", err
   143  	}
   144  	return detectedCreationSources[0], nil
   145  }
   146  
   147  func validateCreationSources(detectedCreationSources []services.SourceType) error {
   148  	if len(detectedCreationSources) == 0 {
   149  		return errorutils.CheckErrorf(missingCreationSourcesErrMsg)
   150  	}
   151  
   152  	// Assert single creation source.
   153  	for i := 1; i < len(detectedCreationSources); i++ {
   154  		if detectedCreationSources[i] != detectedCreationSources[0] {
   155  			return generateSingleCreationSourceErr(detectedCreationSources)
   156  		}
   157  	}
   158  
   159  	// If aql, assert single file.
   160  	if detectedCreationSources[0] == services.Aql && len(detectedCreationSources) > 1 {
   161  		return errorutils.CheckErrorf(singleAqlErrMsg)
   162  	}
   163  	return nil
   164  }
   165  
   166  func generateSingleCreationSourceErr(detectedCreationSources []services.SourceType) error {
   167  	var detectedStr []string
   168  	for _, source := range detectedCreationSources {
   169  		detectedStr = append(detectedStr, string(source))
   170  	}
   171  	return errorutils.CheckErrorf(
   172  		"%s '%s'", multipleCreationSourcesErrMsg, coreutils.ListToText(detectedStr))
   173  }
   174  
   175  func validateFile(file spec.File) (services.SourceType, error) {
   176  	// Aql creation source:
   177  	isAql := len(file.Aql.ItemsFind) > 0
   178  
   179  	// Build creation source:
   180  	isBuild := len(file.Build) > 0
   181  	isIncludeDeps, _ := file.IsIncludeDeps(false)
   182  
   183  	// Bundle creation source:
   184  	isBundle := len(file.Bundle) > 0
   185  
   186  	// Build & bundle:
   187  	isProject := len(file.Project) > 0
   188  
   189  	// Artifacts creation source:
   190  	isPattern := len(file.Pattern) > 0
   191  	isExclusions := len(file.Exclusions) > 0 && len(file.Exclusions[0]) > 0
   192  	isProps := len(file.Props) > 0
   193  	isExcludeProps := len(file.ExcludeProps) > 0
   194  	isRecursive, err := file.IsRecursive(true)
   195  	if err != nil {
   196  		return "", errorutils.CheckErrorf("invalid value provided to the 'recursive' field. error: %s", err.Error())
   197  	}
   198  
   199  	// Unsupported:
   200  	isPathMapping := len(file.PathMapping.Input) > 0 || len(file.PathMapping.Output) > 0
   201  	isTarget := len(file.Target) > 0
   202  	isSortOrder := len(file.SortOrder) > 0
   203  	isSortBy := len(file.SortBy) > 0
   204  	isExcludeArtifacts, _ := file.IsExcludeArtifacts(false)
   205  	isGPGKey := len(file.PublicGpgKey) > 0
   206  	isOffset := file.Offset > 0
   207  	isLimit := file.Limit > 0
   208  	isArchive := len(file.Archive) > 0
   209  	isSymlinks, _ := file.IsSymlinks(false)
   210  	isRegexp := file.Regexp == "true"
   211  	isAnt := file.Ant == "true"
   212  	isExplode, _ := file.IsExplode(false)
   213  	isBypassArchiveInspection, _ := file.IsBypassArchiveInspection(false)
   214  	isTransitive, _ := file.IsTransitive(false)
   215  
   216  	if isPathMapping || isTarget || isSortOrder || isSortBy || isExcludeArtifacts || isGPGKey || isOffset || isLimit ||
   217  		isSymlinks || isArchive || isAnt || isRegexp || isExplode || isBypassArchiveInspection || isTransitive {
   218  		return "", errorutils.CheckErrorf("unsupported fields were provided in file spec. " +
   219  			"release bundle creation file spec only supports the following fields: " +
   220  			"'aql', 'build', 'includeDeps', 'bundle', 'project', 'pattern', 'exclusions', 'props', 'excludeProps' and 'recursive'")
   221  	}
   222  	if coreutils.SumTrueValues([]bool{isAql, isBuild, isBundle, isPattern}) != 1 {
   223  		return "", errorutils.CheckErrorf("exactly one creation source is supported (aql, builds, release bundles or pattern (artifacts))")
   224  	}
   225  
   226  	switch {
   227  	case isAql:
   228  		return services.Aql,
   229  			validateCreationSource([]bool{isIncludeDeps, isProject, isExclusions, isProps, isExcludeProps, !isRecursive},
   230  				"aql creation source supports no other fields")
   231  	case isBuild:
   232  		return services.Builds,
   233  			validateCreationSource([]bool{isExclusions, isProps, isExcludeProps, !isRecursive},
   234  				"builds creation source only supports the 'includeDeps' and 'project' fields")
   235  	case isBundle:
   236  		return services.ReleaseBundles,
   237  			validateCreationSource([]bool{isIncludeDeps, isExclusions, isProps, isExcludeProps, !isRecursive},
   238  				"release bundles creation source only supports the 'project' field")
   239  	case isPattern:
   240  		return services.Artifacts,
   241  			validateCreationSource([]bool{isIncludeDeps, isProject},
   242  				"release bundles creation source only supports the 'exclusions', 'props', 'excludeProps' and 'recursive' fields")
   243  	default:
   244  		return "", errorutils.CheckErrorf("unexpected err in spec validation")
   245  	}
   246  }
   247  
   248  func validateCreationSource(unsupportedFields []bool, errMsg string) error {
   249  	if coreutils.SumTrueValues(unsupportedFields) > 0 {
   250  		return errorutils.CheckErrorf(errMsg)
   251  	}
   252  	return nil
   253  }