github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/commands/buildinfo/publish.go (about) 1 package buildinfo 2 3 import ( 4 "fmt" 5 "github.com/jfrog/jfrog-cli-go/artifactory/utils" 6 "github.com/jfrog/jfrog-cli-go/utils/cliutils" 7 "github.com/jfrog/jfrog-cli-go/utils/config" 8 "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" 9 "github.com/jfrog/jfrog-client-go/utils/errorutils" 10 "path/filepath" 11 "sort" 12 "strings" 13 ) 14 15 type BuildPublishCommand struct { 16 buildConfiguration *utils.BuildConfiguration 17 rtDetails *config.ArtifactoryDetails 18 config *buildinfo.Configuration 19 } 20 21 func NewBuildPublishCommand() *BuildPublishCommand { 22 return &BuildPublishCommand{} 23 } 24 25 func (bpc *BuildPublishCommand) SetConfig(config *buildinfo.Configuration) *BuildPublishCommand { 26 bpc.config = config 27 return bpc 28 } 29 30 func (bpc *BuildPublishCommand) SetRtDetails(rtDetails *config.ArtifactoryDetails) *BuildPublishCommand { 31 bpc.rtDetails = rtDetails 32 return bpc 33 } 34 35 func (bpc *BuildPublishCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *BuildPublishCommand { 36 bpc.buildConfiguration = buildConfiguration 37 return bpc 38 } 39 40 func (bpc *BuildPublishCommand) CommandName() string { 41 return "rt_build_publish" 42 } 43 44 func (bpc *BuildPublishCommand) RtDetails() (*config.ArtifactoryDetails, error) { 45 return bpc.rtDetails, nil 46 } 47 48 func (bpc *BuildPublishCommand) Run() error { 49 servicesManager, err := utils.CreateServiceManager(bpc.rtDetails, bpc.config.DryRun) 50 if err != nil { 51 return err 52 } 53 54 buildInfo, err := bpc.createBuildInfoFromPartials() 55 if err != nil { 56 return err 57 } 58 59 generatedBuildsInfo, err := utils.GetGeneratedBuildsInfo(bpc.buildConfiguration.BuildName, bpc.buildConfiguration.BuildNumber) 60 if err != nil { 61 return err 62 } 63 64 for _, v := range generatedBuildsInfo { 65 buildInfo.Append(v) 66 } 67 68 if err = servicesManager.PublishBuildInfo(buildInfo); err != nil { 69 return err 70 } 71 72 if err = utils.RemoveBuildDir(bpc.buildConfiguration.BuildName, bpc.buildConfiguration.BuildNumber); err != nil { 73 return err 74 } 75 return nil 76 } 77 78 func (bpc *BuildPublishCommand) createBuildInfoFromPartials() (*buildinfo.BuildInfo, error) { 79 buildName := bpc.buildConfiguration.BuildName 80 buildNumber := bpc.buildConfiguration.BuildNumber 81 partials, err := utils.ReadPartialBuildInfoFiles(buildName, buildNumber) 82 if err != nil { 83 return nil, err 84 } 85 sort.Sort(partials) 86 87 buildInfo := buildinfo.New() 88 buildInfo.SetAgentName(cliutils.ClientAgent) 89 buildInfo.SetAgentVersion(cliutils.GetVersion()) 90 buildInfo.SetBuildAgentVersion(cliutils.GetVersion()) 91 buildInfo.SetArtifactoryPluginVersion(cliutils.GetUserAgent()) 92 buildInfo.Name = buildName 93 buildInfo.Number = buildNumber 94 buildGeneralDetails, err := utils.ReadBuildInfoGeneralDetails(buildName, buildNumber) 95 if err != nil { 96 return nil, err 97 } 98 buildInfo.Started = buildGeneralDetails.Timestamp.Format("2006-01-02T15:04:05.000-0700") 99 modules, env, vcs, issues, err := extractBuildInfoData(partials, createIncludeFilter(bpc.config.EnvInclude), createExcludeFilter(bpc.config.EnvExclude)) 100 if err != nil { 101 return nil, err 102 } 103 if len(env) != 0 { 104 buildInfo.Properties = env 105 } 106 buildInfo.ArtifactoryPrincipal = bpc.rtDetails.User 107 buildInfo.BuildUrl = bpc.config.BuildUrl 108 if vcs != (buildinfo.Vcs{}) { 109 buildInfo.Revision = vcs.Revision 110 buildInfo.Url = vcs.Url 111 } 112 // Check for Tracker as it must be set 113 if issues.Tracker != nil && issues.Tracker.Name != "" { 114 buildInfo.Issues = &issues 115 } 116 for _, module := range modules { 117 if module.Id == "" { 118 module.Id = buildName 119 } 120 buildInfo.Modules = append(buildInfo.Modules, module) 121 } 122 return buildInfo, nil 123 } 124 125 func extractBuildInfoData(partials buildinfo.Partials, includeFilter, excludeFilter filterFunc) ([]buildinfo.Module, buildinfo.Env, buildinfo.Vcs, buildinfo.Issues, error) { 126 var vcs buildinfo.Vcs 127 var issues buildinfo.Issues 128 env := make(map[string]string) 129 partialModules := make(map[string]partialModule) 130 issuesMap := make(map[string]*buildinfo.AffectedIssue) 131 for _, partial := range partials { 132 switch { 133 case partial.Artifacts != nil: 134 for _, artifact := range partial.Artifacts { 135 addArtifactToPartialModule(artifact, partial.ModuleId, partialModules) 136 } 137 case partial.Dependencies != nil: 138 for _, dependency := range partial.Dependencies { 139 addDependencyToPartialModule(dependency, partial.ModuleId, partialModules) 140 } 141 case partial.Vcs != nil: 142 vcs = *partial.Vcs 143 if partial.Issues == nil { 144 continue 145 } 146 // Collect issues. 147 issues.Tracker = partial.Issues.Tracker 148 issues.AggregateBuildIssues = partial.Issues.AggregateBuildIssues 149 issues.AggregationBuildStatus = partial.Issues.AggregationBuildStatus 150 // If affected issues exist, add them to issues map 151 if partial.Issues.AffectedIssues != nil { 152 for i, issue := range partial.Issues.AffectedIssues { 153 issuesMap[issue.Key] = &partial.Issues.AffectedIssues[i] 154 } 155 } 156 case partial.Env != nil: 157 envAfterIncludeFilter, e := includeFilter(partial.Env) 158 if errorutils.CheckError(e) != nil { 159 return partialModulesToModules(partialModules), env, vcs, issues, e 160 } 161 envAfterExcludeFilter, e := excludeFilter(envAfterIncludeFilter) 162 if errorutils.CheckError(e) != nil { 163 return partialModulesToModules(partialModules), env, vcs, issues, e 164 } 165 for k, v := range envAfterExcludeFilter { 166 env[k] = v 167 } 168 } 169 } 170 return partialModulesToModules(partialModules), env, vcs, issuesMapToArray(issues, issuesMap), nil 171 } 172 173 func partialModulesToModules(partialModules map[string]partialModule) []buildinfo.Module { 174 var modules []buildinfo.Module 175 for moduleId, singlePartialModule := range partialModules { 176 moduleArtifacts := artifactsMapToList(singlePartialModule.artifacts) 177 moduleDependencies := dependenciesMapToList(singlePartialModule.dependencies) 178 modules = append(modules, *createModule(moduleId, moduleArtifacts, moduleDependencies)) 179 } 180 return modules 181 } 182 183 func issuesMapToArray(issues buildinfo.Issues, issuesMap map[string]*buildinfo.AffectedIssue) buildinfo.Issues { 184 for _, issue := range issuesMap { 185 issues.AffectedIssues = append(issues.AffectedIssues, *issue) 186 } 187 return issues 188 } 189 190 func addDependencyToPartialModule(dependency buildinfo.Dependency, moduleId string, partialModules map[string]partialModule) { 191 // init map if needed 192 if partialModules[moduleId].dependencies == nil { 193 partialModules[moduleId] = 194 partialModule{artifacts: partialModules[moduleId].artifacts, 195 dependencies: make(map[string]buildinfo.Dependency)} 196 } 197 key := fmt.Sprintf("%s-%s-%s-%s", dependency.Id, dependency.Sha1, dependency.Md5, dependency.Scopes) 198 partialModules[moduleId].dependencies[key] = dependency 199 } 200 201 func addArtifactToPartialModule(artifact buildinfo.Artifact, moduleId string, partialModules map[string]partialModule) { 202 // init map if needed 203 if partialModules[moduleId].artifacts == nil { 204 partialModules[moduleId] = 205 partialModule{artifacts: make(map[string]buildinfo.Artifact), 206 dependencies: partialModules[moduleId].dependencies} 207 } 208 key := fmt.Sprintf("%s-%s-%s", artifact.Name, artifact.Sha1, artifact.Md5) 209 partialModules[moduleId].artifacts[key] = artifact 210 } 211 212 func artifactsMapToList(artifactsMap map[string]buildinfo.Artifact) []buildinfo.Artifact { 213 var artifacts []buildinfo.Artifact 214 for _, artifact := range artifactsMap { 215 artifacts = append(artifacts, artifact) 216 } 217 return artifacts 218 } 219 220 func dependenciesMapToList(dependenciesMap map[string]buildinfo.Dependency) []buildinfo.Dependency { 221 var dependencies []buildinfo.Dependency 222 for _, dependency := range dependenciesMap { 223 dependencies = append(dependencies, dependency) 224 } 225 return dependencies 226 } 227 228 func createModule(moduleId string, artifacts []buildinfo.Artifact, dependencies []buildinfo.Dependency) *buildinfo.Module { 229 module := createDefaultModule(moduleId) 230 if artifacts != nil && len(artifacts) > 0 { 231 module.Artifacts = append(module.Artifacts, artifacts...) 232 } 233 if dependencies != nil && len(dependencies) > 0 { 234 module.Dependencies = append(module.Dependencies, dependencies...) 235 } 236 return module 237 } 238 239 func createDefaultModule(moduleId string) *buildinfo.Module { 240 return &buildinfo.Module{ 241 Id: moduleId, 242 Properties: map[string][]string{}, 243 Artifacts: []buildinfo.Artifact{}, 244 Dependencies: []buildinfo.Dependency{}, 245 } 246 } 247 248 type filterFunc func(map[string]string) (map[string]string, error) 249 250 func createIncludeFilter(pattern string) filterFunc { 251 includePattern := strings.Split(pattern, ";") 252 return func(tempMap map[string]string) (map[string]string, error) { 253 result := make(map[string]string) 254 for k, v := range tempMap { 255 for _, filterPattern := range includePattern { 256 matched, err := filepath.Match(strings.ToLower(filterPattern), strings.ToLower(k)) 257 if errorutils.CheckError(err) != nil { 258 return nil, err 259 } 260 if matched { 261 result[k] = v 262 break 263 } 264 } 265 } 266 return result, nil 267 } 268 } 269 270 func createExcludeFilter(pattern string) filterFunc { 271 excludePattern := strings.Split(pattern, ";") 272 return func(tempMap map[string]string) (map[string]string, error) { 273 result := make(map[string]string) 274 for k, v := range tempMap { 275 include := true 276 for _, filterPattern := range excludePattern { 277 matched, err := filepath.Match(strings.ToLower(filterPattern), strings.ToLower(k)) 278 if errorutils.CheckError(err) != nil { 279 return nil, err 280 } 281 if matched { 282 include = false 283 break 284 } 285 } 286 if include { 287 result[k] = v 288 } 289 } 290 return result, nil 291 } 292 } 293 294 type partialModule struct { 295 artifacts map[string]buildinfo.Artifact 296 dependencies map[string]buildinfo.Dependency 297 }