github.com/jfrog/jfrog-cli-core@v1.12.1/artifactory/commands/buildinfo/buildappend.go (about) 1 package buildinfo 2 3 import ( 4 "errors" 5 "net/http" 6 "strconv" 7 "time" 8 9 "github.com/jfrog/jfrog-cli-core/artifactory/utils" 10 "github.com/jfrog/jfrog-cli-core/utils/config" 11 "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" 12 "github.com/jfrog/jfrog-client-go/artifactory/services" 13 "github.com/jfrog/jfrog-client-go/http/httpclient" 14 "github.com/jfrog/jfrog-client-go/utils/errorutils" 15 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 16 "github.com/jfrog/jfrog-client-go/utils/log" 17 ) 18 19 type BuildAppendCommand struct { 20 buildConfiguration *utils.BuildConfiguration 21 serverDetails *config.ServerDetails 22 buildNameToAppend string 23 buildNumberToAppend string 24 } 25 26 func NewBuildAppendCommand() *BuildAppendCommand { 27 return &BuildAppendCommand{} 28 } 29 30 func (bac *BuildAppendCommand) CommandName() string { 31 return "rt_build_append" 32 } 33 34 func (bac *BuildAppendCommand) ServerDetails() (*config.ServerDetails, error) { 35 return config.GetDefaultServerConf() 36 } 37 38 func (bac *BuildAppendCommand) Run() error { 39 log.Info("Running Build Append command...") 40 if err := utils.SaveBuildGeneralDetails(bac.buildConfiguration.BuildName, bac.buildConfiguration.BuildNumber, bac.buildConfiguration.Project); err != nil { 41 return err 42 } 43 44 // Calculate build timestamp 45 timestamp, err := bac.getBuildTimestamp() 46 if err != nil { 47 return err 48 } 49 50 // Get checksum headers from the build info artifact 51 checksumDetails, err := bac.getChecksumDetails(timestamp) 52 if err != nil { 53 return err 54 } 55 56 log.Debug("Appending build", bac.buildNameToAppend+"/"+bac.buildNumberToAppend, "to build info") 57 populateFunc := func(partial *buildinfo.Partial) { 58 partial.ModuleType = buildinfo.Build 59 partial.ModuleId = bac.buildNameToAppend + "/" + bac.buildNumberToAppend 60 partial.Checksum = buildinfo.Checksum{ 61 Sha1: checksumDetails.Sha1, 62 Md5: checksumDetails.Md5, 63 } 64 } 65 err = utils.SavePartialBuildInfo(bac.buildConfiguration.BuildName, bac.buildConfiguration.BuildNumber, bac.buildConfiguration.Project, populateFunc) 66 if err == nil { 67 log.Info("Build", bac.buildNameToAppend+"/"+bac.buildNumberToAppend, "successfully appended to", bac.buildConfiguration.BuildName+"/"+bac.buildConfiguration.BuildNumber) 68 } 69 return err 70 } 71 72 func (bac *BuildAppendCommand) SetServerDetails(serverDetails *config.ServerDetails) *BuildAppendCommand { 73 bac.serverDetails = serverDetails 74 return bac 75 } 76 77 func (bac *BuildAppendCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *BuildAppendCommand { 78 bac.buildConfiguration = buildConfiguration 79 return bac 80 } 81 82 func (bac *BuildAppendCommand) SetBuildNameToAppend(buildName string) *BuildAppendCommand { 83 bac.buildNameToAppend = buildName 84 return bac 85 } 86 87 func (bac *BuildAppendCommand) SetBuildNumberToAppend(buildNumber string) *BuildAppendCommand { 88 bac.buildNumberToAppend = buildNumber 89 return bac 90 } 91 92 // Get build timestamp of the build to append. The build timestamp has to be converted to milliseconds from epoch. 93 // For example, start time of: 2020-11-27T14:33:38.538+0200 should be converted to 1606480418538. 94 func (bac *BuildAppendCommand) getBuildTimestamp() (int64, error) { 95 // Create services manager to get build-info from Artifactory. 96 sm, err := utils.CreateServiceManager(bac.serverDetails, -1, false) 97 if err != nil { 98 return 0, err 99 } 100 101 // Get published build-info from Artifactory. 102 buildInfoParams := services.BuildInfoParams{BuildName: bac.buildNameToAppend, BuildNumber: bac.buildNumberToAppend} 103 buildInfo, found, err := sm.GetBuildInfo(buildInfoParams) 104 if err != nil { 105 return 0, err 106 } 107 if !found { 108 return 0, errorutils.CheckError(errors.New("Build " + bac.buildNameToAppend + "/" + bac.buildNumberToAppend + " not found in Artifactory.")) 109 } 110 111 buildTime, err := time.Parse(buildinfo.TimeFormat, buildInfo.BuildInfo.Started) 112 if errorutils.CheckError(err) != nil { 113 return 0, err 114 } 115 116 // Convert from nanoseconds to milliseconds 117 timestamp := buildTime.UnixNano() / 1000000 118 log.Debug("Build " + bac.buildNameToAppend + "/" + bac.buildNumberToAppend + ". Started: " + buildInfo.BuildInfo.Started + ". Calculated timestamp: " + strconv.FormatInt(timestamp, 10)) 119 120 return timestamp, err 121 } 122 123 // Download MD5 and SHA1 from the build info artifact. 124 func (bac *BuildAppendCommand) getChecksumDetails(timestamp int64) (fileutils.ChecksumDetails, error) { 125 serviceDetails, err := bac.serverDetails.CreateArtAuthConfig() 126 client, err := httpclient.ClientBuilder().SetRetries(3).Build() 127 if err != nil { 128 return fileutils.ChecksumDetails{}, err 129 } 130 131 buildInfoRepo := "artifactory-build-info" 132 if bac.buildConfiguration.Project != "" { 133 buildInfoRepo = bac.buildConfiguration.Project + "-build-info" 134 } 135 buildInfoPath := serviceDetails.GetUrl() + buildInfoRepo + "/" + bac.buildNameToAppend + "/" + bac.buildNumberToAppend + "-" + strconv.FormatInt(timestamp, 10) + ".json" 136 details, resp, err := client.GetRemoteFileDetails(buildInfoPath, serviceDetails.CreateHttpClientDetails()) 137 if err != nil { 138 return fileutils.ChecksumDetails{}, err 139 } 140 log.Debug("Artifactory response: ", resp.Status) 141 err = errorutils.CheckResponseStatus(resp, http.StatusOK) 142 if errorutils.CheckError(err) != nil { 143 return fileutils.ChecksumDetails{}, err 144 } 145 146 return details.Checksum, nil 147 }