github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/commands/buildinfo/publish.go (about) 1 package buildinfo 2 3 import ( 4 "fmt" 5 "sort" 6 7 "github.com/jfrog/jfrog-cli-core/artifactory/utils" 8 "github.com/jfrog/jfrog-cli-core/utils/config" 9 "github.com/jfrog/jfrog-cli-core/utils/coreutils" 10 "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" 11 "github.com/jfrog/jfrog-client-go/utils/errorutils" 12 ) 13 14 type BuildPublishCommand struct { 15 buildConfiguration *utils.BuildConfiguration 16 rtDetails *config.ArtifactoryDetails 17 config *buildinfo.Configuration 18 } 19 20 func NewBuildPublishCommand() *BuildPublishCommand { 21 return &BuildPublishCommand{} 22 } 23 24 func (bpc *BuildPublishCommand) SetConfig(config *buildinfo.Configuration) *BuildPublishCommand { 25 bpc.config = config 26 return bpc 27 } 28 29 func (bpc *BuildPublishCommand) SetRtDetails(rtDetails *config.ArtifactoryDetails) *BuildPublishCommand { 30 bpc.rtDetails = rtDetails 31 return bpc 32 } 33 34 func (bpc *BuildPublishCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *BuildPublishCommand { 35 bpc.buildConfiguration = buildConfiguration 36 return bpc 37 } 38 39 func (bpc *BuildPublishCommand) CommandName() string { 40 return "rt_build_publish" 41 } 42 43 func (bpc *BuildPublishCommand) RtDetails() (*config.ArtifactoryDetails, error) { 44 return bpc.rtDetails, nil 45 } 46 47 func (bpc *BuildPublishCommand) Run() error { 48 servicesManager, err := utils.CreateServiceManager(bpc.rtDetails, bpc.config.DryRun) 49 if err != nil { 50 return err 51 } 52 53 buildInfo, err := bpc.createBuildInfoFromPartials() 54 if err != nil { 55 return err 56 } 57 58 generatedBuildsInfo, err := utils.GetGeneratedBuildsInfo(bpc.buildConfiguration.BuildName, bpc.buildConfiguration.BuildNumber) 59 if err != nil { 60 return err 61 } 62 63 for _, v := range generatedBuildsInfo { 64 buildInfo.Append(v) 65 } 66 67 project := utils.GetBuildProject(bpc.buildConfiguration.Project) 68 if err = servicesManager.PublishBuildInfo(buildInfo, project); err != nil { 69 return err 70 } 71 72 if !bpc.config.DryRun { 73 return utils.RemoveBuildDir(bpc.buildConfiguration.BuildName, bpc.buildConfiguration.BuildNumber) 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(coreutils.GetClientAgent()) 89 buildInfo.SetAgentVersion(coreutils.GetVersion()) 90 buildInfo.SetBuildAgentVersion(coreutils.GetVersion()) 91 buildInfo.SetArtifactoryPluginVersion(coreutils.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(buildinfo.TimeFormat) 99 modules, env, vcsList, issues, err := extractBuildInfoData(partials, bpc.config.IncludeFilter(), bpc.config.ExcludeFilter()) 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 for _, vcs := range vcsList { 109 buildInfo.VcsList = append(buildInfo.VcsList, vcs) 110 } 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 buildinfo.Filter) ([]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.VcsList != nil: 142 for _, partialVcs := range partial.VcsList { 143 vcs = append(vcs, partialVcs) 144 } 145 if partial.Issues == nil { 146 continue 147 } 148 // Collect issues. 149 issues.Tracker = partial.Issues.Tracker 150 issues.AggregateBuildIssues = partial.Issues.AggregateBuildIssues 151 issues.AggregationBuildStatus = partial.Issues.AggregationBuildStatus 152 // If affected issues exist, add them to issues map 153 if partial.Issues.AffectedIssues != nil { 154 for i, issue := range partial.Issues.AffectedIssues { 155 issuesMap[issue.Key] = &partial.Issues.AffectedIssues[i] 156 } 157 } 158 case partial.Env != nil: 159 envAfterIncludeFilter, e := includeFilter(partial.Env) 160 if errorutils.CheckError(e) != nil { 161 return partialModulesToModules(partialModules), env, vcs, issues, e 162 } 163 envAfterExcludeFilter, e := excludeFilter(envAfterIncludeFilter) 164 if errorutils.CheckError(e) != nil { 165 return partialModulesToModules(partialModules), env, vcs, issues, e 166 } 167 for k, v := range envAfterExcludeFilter { 168 env[k] = v 169 } 170 case partial.ModuleType == buildinfo.Build: 171 partialModules[partial.ModuleId] = partialModule{ 172 moduleType: partial.ModuleType, 173 checksum: partial.Checksum, 174 } 175 } 176 } 177 return partialModulesToModules(partialModules), env, vcs, issuesMapToArray(issues, issuesMap), nil 178 } 179 180 func partialModulesToModules(partialModules map[string]partialModule) []buildinfo.Module { 181 var modules []buildinfo.Module 182 for moduleId, singlePartialModule := range partialModules { 183 moduleArtifacts := artifactsMapToList(singlePartialModule.artifacts) 184 moduleDependencies := dependenciesMapToList(singlePartialModule.dependencies) 185 modules = append(modules, *createModule(moduleId, singlePartialModule.moduleType, singlePartialModule.checksum, moduleArtifacts, moduleDependencies)) 186 } 187 return modules 188 } 189 190 func issuesMapToArray(issues buildinfo.Issues, issuesMap map[string]*buildinfo.AffectedIssue) buildinfo.Issues { 191 for _, issue := range issuesMap { 192 issues.AffectedIssues = append(issues.AffectedIssues, *issue) 193 } 194 return issues 195 } 196 197 func addDependencyToPartialModule(dependency buildinfo.Dependency, moduleId string, partialModules map[string]partialModule) { 198 // init map if needed 199 if partialModules[moduleId].dependencies == nil { 200 partialModules[moduleId] = 201 partialModule{artifacts: partialModules[moduleId].artifacts, 202 dependencies: make(map[string]buildinfo.Dependency)} 203 } 204 key := fmt.Sprintf("%s-%s-%s-%s", dependency.Id, dependency.Sha1, dependency.Md5, dependency.Scopes) 205 partialModules[moduleId].dependencies[key] = dependency 206 } 207 208 func addArtifactToPartialModule(artifact buildinfo.Artifact, moduleId string, partialModules map[string]partialModule) { 209 // init map if needed 210 if partialModules[moduleId].artifacts == nil { 211 partialModules[moduleId] = 212 partialModule{artifacts: make(map[string]buildinfo.Artifact), 213 dependencies: partialModules[moduleId].dependencies} 214 } 215 key := fmt.Sprintf("%s-%s-%s", artifact.Name, artifact.Sha1, artifact.Md5) 216 partialModules[moduleId].artifacts[key] = artifact 217 } 218 219 func artifactsMapToList(artifactsMap map[string]buildinfo.Artifact) []buildinfo.Artifact { 220 var artifacts []buildinfo.Artifact 221 for _, artifact := range artifactsMap { 222 artifacts = append(artifacts, artifact) 223 } 224 return artifacts 225 } 226 227 func dependenciesMapToList(dependenciesMap map[string]buildinfo.Dependency) []buildinfo.Dependency { 228 var dependencies []buildinfo.Dependency 229 for _, dependency := range dependenciesMap { 230 dependencies = append(dependencies, dependency) 231 } 232 return dependencies 233 } 234 235 func createModule(moduleId string, moduleType buildinfo.ModuleType, checksum *buildinfo.Checksum, artifacts []buildinfo.Artifact, dependencies []buildinfo.Dependency) *buildinfo.Module { 236 module := createDefaultModule(moduleId) 237 module.Type = moduleType 238 module.Checksum = checksum 239 if artifacts != nil && len(artifacts) > 0 { 240 module.Artifacts = append(module.Artifacts, artifacts...) 241 } 242 if dependencies != nil && len(dependencies) > 0 { 243 module.Dependencies = append(module.Dependencies, dependencies...) 244 } 245 return module 246 } 247 248 func createDefaultModule(moduleId string) *buildinfo.Module { 249 return &buildinfo.Module{ 250 Id: moduleId, 251 Properties: map[string][]string{}, 252 Artifacts: []buildinfo.Artifact{}, 253 Dependencies: []buildinfo.Dependency{}, 254 } 255 } 256 257 type partialModule struct { 258 moduleType buildinfo.ModuleType 259 artifacts map[string]buildinfo.Artifact 260 dependencies map[string]buildinfo.Dependency 261 checksum *buildinfo.Checksum 262 }