github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/buildinfo/publish.go (about) 1 package buildinfo 2 3 import ( 4 "errors" 5 "fmt" 6 "net/url" 7 "strconv" 8 "strings" 9 "time" 10 11 buildinfo "github.com/jfrog/build-info-go/entities" 12 "github.com/jfrog/jfrog-cli-core/v2/artifactory/formats" 13 "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" 14 "github.com/jfrog/jfrog-cli-core/v2/common/build" 15 "github.com/jfrog/jfrog-cli-core/v2/utils/config" 16 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" 17 "github.com/jfrog/jfrog-client-go/artifactory" 18 biconf "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" 19 "github.com/jfrog/jfrog-client-go/artifactory/services" 20 artclientutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" 21 clientutils "github.com/jfrog/jfrog-client-go/utils" 22 "github.com/jfrog/jfrog-client-go/utils/errorutils" 23 "github.com/jfrog/jfrog-client-go/utils/log" 24 ) 25 26 type BuildPublishCommand struct { 27 buildConfiguration *build.BuildConfiguration 28 serverDetails *config.ServerDetails 29 config *biconf.Configuration 30 detailedSummary bool 31 summary *clientutils.Sha256Summary 32 } 33 34 func NewBuildPublishCommand() *BuildPublishCommand { 35 return &BuildPublishCommand{} 36 } 37 38 func (bpc *BuildPublishCommand) SetConfig(config *biconf.Configuration) *BuildPublishCommand { 39 bpc.config = config 40 return bpc 41 } 42 43 func (bpc *BuildPublishCommand) SetServerDetails(serverDetails *config.ServerDetails) *BuildPublishCommand { 44 bpc.serverDetails = serverDetails 45 return bpc 46 } 47 48 func (bpc *BuildPublishCommand) SetBuildConfiguration(buildConfiguration *build.BuildConfiguration) *BuildPublishCommand { 49 bpc.buildConfiguration = buildConfiguration 50 return bpc 51 } 52 53 func (bpc *BuildPublishCommand) SetSummary(summary *clientutils.Sha256Summary) *BuildPublishCommand { 54 bpc.summary = summary 55 return bpc 56 } 57 58 func (bpc *BuildPublishCommand) GetSummary() *clientutils.Sha256Summary { 59 return bpc.summary 60 } 61 62 func (bpc *BuildPublishCommand) SetDetailedSummary(detailedSummary bool) *BuildPublishCommand { 63 bpc.detailedSummary = detailedSummary 64 return bpc 65 } 66 67 func (bpc *BuildPublishCommand) IsDetailedSummary() bool { 68 return bpc.detailedSummary 69 } 70 71 func (bpc *BuildPublishCommand) CommandName() string { 72 return "rt_build_publish" 73 } 74 75 func (bpc *BuildPublishCommand) ServerDetails() (*config.ServerDetails, error) { 76 return bpc.serverDetails, nil 77 } 78 79 func (bpc *BuildPublishCommand) Run() error { 80 servicesManager, err := utils.CreateServiceManager(bpc.serverDetails, -1, 0, bpc.config.DryRun) 81 if err != nil { 82 return err 83 } 84 85 buildInfoService := build.CreateBuildInfoService() 86 buildName, err := bpc.buildConfiguration.GetBuildName() 87 if err != nil { 88 return err 89 } 90 buildNumber, err := bpc.buildConfiguration.GetBuildNumber() 91 if err != nil { 92 return err 93 } 94 build, err := buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, bpc.buildConfiguration.GetProject()) 95 if errorutils.CheckError(err) != nil { 96 return err 97 } 98 99 build.SetAgentName(coreutils.GetCliUserAgentName()) 100 build.SetAgentVersion(coreutils.GetCliUserAgentVersion()) 101 build.SetBuildAgentVersion(coreutils.GetClientAgentVersion()) 102 build.SetPrincipal(bpc.serverDetails.User) 103 build.SetBuildUrl(bpc.config.BuildUrl) 104 105 buildInfo, err := build.ToBuildInfo() 106 if errorutils.CheckError(err) != nil { 107 return err 108 } 109 err = buildInfo.IncludeEnv(strings.Split(bpc.config.EnvInclude, ";")...) 110 if errorutils.CheckError(err) != nil { 111 return err 112 } 113 err = buildInfo.ExcludeEnv(strings.Split(bpc.config.EnvExclude, ";")...) 114 if errorutils.CheckError(err) != nil { 115 return err 116 } 117 if bpc.buildConfiguration.IsLoadedFromConfigFile() { 118 buildInfo.Number, err = bpc.getNextBuildNumber(buildInfo.Name, servicesManager) 119 if errorutils.CheckError(err) != nil { 120 return err 121 } 122 bpc.buildConfiguration.SetBuildNumber(buildInfo.Number) 123 } 124 summary, err := servicesManager.PublishBuildInfo(buildInfo, bpc.buildConfiguration.GetProject()) 125 if bpc.IsDetailedSummary() { 126 bpc.SetSummary(summary) 127 } 128 if err != nil || bpc.config.DryRun { 129 return err 130 } 131 132 buildLink, err := bpc.constructBuildInfoUiUrl(servicesManager, buildInfo.Started) 133 if err != nil { 134 return err 135 } 136 137 err = build.Clean() 138 if err != nil { 139 return err 140 } 141 142 logMsg := "Build info successfully deployed." 143 if bpc.IsDetailedSummary() { 144 log.Info(logMsg + " Browse it in Artifactory under " + buildLink) 145 return nil 146 } 147 148 log.Info(logMsg) 149 return logJsonOutput(buildLink) 150 } 151 152 func logJsonOutput(buildInfoUiUrl string) error { 153 output := formats.BuildPublishOutput{BuildInfoUiUrl: buildInfoUiUrl} 154 results, err := output.JSON() 155 if err != nil { 156 return errorutils.CheckError(err) 157 } 158 log.Output(clientutils.IndentJson(results)) 159 return nil 160 } 161 162 func (bpc *BuildPublishCommand) constructBuildInfoUiUrl(servicesManager artifactory.ArtifactoryServicesManager, buildInfoStarted string) (string, error) { 163 buildTime, err := time.Parse(buildinfo.TimeFormat, buildInfoStarted) 164 if errorutils.CheckError(err) != nil { 165 return "", err 166 } 167 artVersion, err := servicesManager.GetVersion() 168 if err != nil { 169 return "", err 170 } 171 artVersionSlice := strings.Split(artVersion, ".") 172 majorVersion, err := strconv.Atoi(artVersionSlice[0]) 173 if errorutils.CheckError(err) != nil { 174 return "", err 175 } 176 return bpc.getBuildInfoUiUrl(majorVersion, buildTime) 177 } 178 179 func (bpc *BuildPublishCommand) getBuildInfoUiUrl(majorVersion int, buildTime time.Time) (string, error) { 180 buildName, err := bpc.buildConfiguration.GetBuildName() 181 if err != nil { 182 return "", err 183 } 184 buildNumber, err := bpc.buildConfiguration.GetBuildNumber() 185 if err != nil { 186 return "", err 187 } 188 189 baseUrl := bpc.serverDetails.GetUrl() 190 if baseUrl == "" { 191 baseUrl = strings.TrimSuffix(strings.TrimSuffix(bpc.serverDetails.GetArtifactoryUrl(), "/"), "artifactory") 192 } 193 baseUrl = clientutils.AddTrailingSlashIfNeeded(baseUrl) 194 195 project := bpc.buildConfiguration.GetProject() 196 buildName, buildNumber, project = url.PathEscape(buildName), url.PathEscape(buildNumber), url.QueryEscape(project) 197 198 if majorVersion <= 6 { 199 return fmt.Sprintf("%vartifactory/webapp/#/builds/%v/%v", 200 baseUrl, buildName, buildNumber), nil 201 } 202 timestamp := buildTime.UnixMilli() 203 if project != "" { 204 return fmt.Sprintf("%vui/builds/%v/%v/%v/published?buildRepo=%v-build-info&projectKey=%v", 205 baseUrl, buildName, buildNumber, strconv.FormatInt(timestamp, 10), project, project), nil 206 } 207 return fmt.Sprintf("%vui/builds/%v/%v/%v/published?buildRepo=artifactory-build-info", 208 baseUrl, buildName, buildNumber, strconv.FormatInt(timestamp, 10)), nil 209 } 210 211 // Return the next build number based on the previously published build. 212 // Return "1" if no build is found 213 func (bpc *BuildPublishCommand) getNextBuildNumber(buildName string, servicesManager artifactory.ArtifactoryServicesManager) (string, error) { 214 publishedBuildInfo, found, err := servicesManager.GetBuildInfo(services.BuildInfoParams{BuildName: buildName, BuildNumber: artclientutils.LatestBuildNumberKey}) 215 if err != nil { 216 return "", err 217 } 218 if !found || publishedBuildInfo.BuildInfo.Number == "" { 219 return "1", nil 220 } 221 latestBuildNumber, err := strconv.Atoi(publishedBuildInfo.BuildInfo.Number) 222 if errorutils.CheckError(err) != nil { 223 if errors.Is(err, strconv.ErrSyntax) { 224 log.Warn("The latest build number is " + publishedBuildInfo.BuildInfo.Number + ". Since it is not an integer, and therefore cannot be incremented to automatically generate the next build number, setting the next build number to 1.") 225 return "1", nil 226 } 227 return "", err 228 } 229 latestBuildNumber++ 230 return strconv.Itoa(latestBuildNumber), nil 231 }