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 }