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  }