github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/commands/golang/go.go (about)

     1  package golang
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"path"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/jfrog/gocmd"
    11  	executersutils "github.com/jfrog/gocmd/executers/utils"
    12  	"github.com/jfrog/gocmd/params"
    13  	"github.com/jfrog/jfrog-cli-core/artifactory/utils"
    14  	"github.com/jfrog/jfrog-cli-core/artifactory/utils/golang"
    15  	"github.com/jfrog/jfrog-cli-core/artifactory/utils/golang/project"
    16  	"github.com/jfrog/jfrog-cli-core/utils/config"
    17  	"github.com/jfrog/jfrog-client-go/artifactory"
    18  	_go "github.com/jfrog/jfrog-client-go/artifactory/services/go"
    19  	"github.com/jfrog/jfrog-client-go/auth"
    20  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    21  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    22  	"github.com/jfrog/jfrog-client-go/utils/version"
    23  )
    24  
    25  const GoCommandName = "rt_go"
    26  
    27  type GoCommand struct {
    28  	noRegistry         bool
    29  	publishDeps        bool
    30  	goArg              []string
    31  	buildConfiguration *utils.BuildConfiguration
    32  	deployerParams     *utils.RepositoryConfig
    33  	resolverParams     *utils.RepositoryConfig
    34  }
    35  
    36  func NewGoCommand() *GoCommand {
    37  	return &GoCommand{}
    38  }
    39  
    40  func (gc *GoCommand) SetResolverParams(resolverParams *utils.RepositoryConfig) *GoCommand {
    41  	gc.resolverParams = resolverParams
    42  	return gc
    43  }
    44  
    45  func (gc *GoCommand) SetDeployerParams(deployerParams *utils.RepositoryConfig) *GoCommand {
    46  	gc.deployerParams = deployerParams
    47  	return gc
    48  }
    49  
    50  func (gc *GoCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *GoCommand {
    51  	gc.buildConfiguration = buildConfiguration
    52  	return gc
    53  }
    54  
    55  func (gc *GoCommand) SetNoRegistry(noRegistry bool) *GoCommand {
    56  	gc.noRegistry = noRegistry
    57  	return gc
    58  }
    59  
    60  func (gc *GoCommand) SetPublishDeps(publishDeps bool) *GoCommand {
    61  	gc.publishDeps = publishDeps
    62  	return gc
    63  }
    64  
    65  func (gc *GoCommand) SetGoArg(goArg []string) *GoCommand {
    66  	gc.goArg = goArg
    67  	return gc
    68  }
    69  
    70  func (gc *GoCommand) RtDetails() (*config.ArtifactoryDetails, error) {
    71  	if gc.deployerParams != nil && !gc.deployerParams.IsRtDetailsEmpty() {
    72  		return gc.deployerParams.RtDetails()
    73  	}
    74  	return gc.resolverParams.RtDetails()
    75  }
    76  
    77  func (gc *GoCommand) CommandName() string {
    78  	return GoCommandName
    79  }
    80  
    81  func (gc *GoCommand) Run() error {
    82  	err := golang.LogGoVersion()
    83  	if err != nil {
    84  		return err
    85  	}
    86  	buildName := gc.buildConfiguration.BuildName
    87  	buildNumber := gc.buildConfiguration.BuildNumber
    88  	isCollectBuildInfo := len(buildName) > 0 && len(buildNumber) > 0
    89  	if isCollectBuildInfo {
    90  		err = utils.SaveBuildGeneralDetails(buildName, buildNumber)
    91  		if err != nil {
    92  			return err
    93  		}
    94  	}
    95  
    96  	resolverDetails, err := gc.resolverParams.RtDetails()
    97  	if err != nil {
    98  		return err
    99  	}
   100  	resolverServiceManager, err := utils.CreateServiceManager(resolverDetails, false)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	resolverParams := &params.Params{}
   105  	resolverParams.SetRepo(gc.resolverParams.TargetRepo()).SetServiceManager(resolverServiceManager)
   106  	goInfo := &params.ResolverDeployer{}
   107  	goInfo.SetResolver(resolverParams)
   108  	var targetRepo string
   109  	var deployerServiceManager artifactory.ArtifactoryServicesManager
   110  	if gc.publishDeps {
   111  		deployerDetails, err := gc.deployerParams.RtDetails()
   112  		if err != nil {
   113  			return err
   114  		}
   115  		deployerServiceManager, err = utils.CreateServiceManager(deployerDetails, false)
   116  		if err != nil {
   117  			return err
   118  		}
   119  		targetRepo = gc.deployerParams.TargetRepo()
   120  		deployerParams := &params.Params{}
   121  		deployerParams.SetRepo(targetRepo).SetServiceManager(deployerServiceManager)
   122  		goInfo.SetDeployer(deployerParams)
   123  	}
   124  
   125  	err = gocmd.RunWithFallbacksAndPublish(gc.goArg, gc.noRegistry, gc.publishDeps, goInfo)
   126  	if err != nil {
   127  		return err
   128  	}
   129  	if isCollectBuildInfo {
   130  		tempDirPath := ""
   131  		if isGoGetCommand := len(gc.goArg) > 0 && gc.goArg[0] == "get"; isGoGetCommand {
   132  			if len(gc.goArg) < 2 {
   133  				// Package name was not supplied. Invalid go get commend
   134  				return errorutils.CheckError(errors.New("Invalid get command. Package name is missing"))
   135  			}
   136  			tempDirPath, err = fileutils.CreateTempDir()
   137  			if err != nil {
   138  				return err
   139  			}
   140  			// Cleanup the temp working directory at the end.
   141  			defer fileutils.RemoveTempDir(tempDirPath)
   142  			// Get Artifactory config in order to extract the package version.
   143  			rtDetails, err := resolverDetails.CreateArtAuthConfig()
   144  			if err != nil {
   145  				return err
   146  			}
   147  			err = copyGoPackageFiles(tempDirPath, gc.goArg[1], gc.resolverParams.TargetRepo(), rtDetails)
   148  			if err != nil {
   149  				return err
   150  			}
   151  		}
   152  		goProject, err := project.Load("-", tempDirPath)
   153  		if err != nil {
   154  			return err
   155  		}
   156  		includeInfoFiles, err := shouldIncludeInfoFiles(deployerServiceManager, resolverServiceManager)
   157  		if err != nil {
   158  			return err
   159  		}
   160  		err = goProject.LoadDependencies()
   161  		if err != nil {
   162  			return err
   163  		}
   164  		err = goProject.CreateBuildInfoDependencies(includeInfoFiles)
   165  		if err != nil {
   166  			return err
   167  		}
   168  		err = utils.SaveBuildInfo(buildName, buildNumber, goProject.BuildInfo(false, gc.buildConfiguration.Module, targetRepo))
   169  	}
   170  
   171  	return err
   172  }
   173  
   174  // copyGoPackageFiles copies the package files from the go mod cache directory to the given destPath.
   175  // The path to those chache files is retrived using the supplied package name and Artifactory details.
   176  func copyGoPackageFiles(destPath, packageName, rtTargetRepo string, rtDetails auth.ServiceDetails) error {
   177  	packageFilesPath, err := getPackageFilePathFromArtifactory(packageName, rtTargetRepo, rtDetails)
   178  	if err != nil {
   179  		return err
   180  	}
   181  	// Copy the entire content of the relevant Go pkg directory to the requested destination path.
   182  	err = fileutils.CopyDir(packageFilesPath, destPath, true, nil)
   183  	if err != nil {
   184  		return fmt.Errorf("Couldn't find suitable package files: %s", packageFilesPath)
   185  	}
   186  	return nil
   187  }
   188  
   189  // getPackageFilePathFromArtifactory returns a string that represents the package files chache path.
   190  // In most cases the path to those chache files is retrived using the supplied package name and Artifactory details.
   191  // However if the user asked for a specifc version (package@vX.Y.Z) the unnecessary call to Artifactpry is avoided.
   192  func getPackageFilePathFromArtifactory(packageName, rtTargetRepo string, rtDetails auth.ServiceDetails) (packageFilesPath string, err error) {
   193  	var version string
   194  	packageCachePath, err := executersutils.GetGoModCachePath()
   195  	if err != nil {
   196  		return
   197  	}
   198  	packageNameSplitted := strings.Split(packageName, "@")
   199  	name := packageNameSplitted[0]
   200  	// The case the user asks for a specifc version
   201  	if len(packageNameSplitted) == 2 && strings.HasPrefix(packageNameSplitted[1], "v") {
   202  		version = packageNameSplitted[1]
   203  	} else {
   204  		branchName := ""
   205  		// The case the user asks for a specifc branch
   206  		if len(packageNameSplitted) == 2 {
   207  			branchName = packageNameSplitted[1]
   208  		}
   209  		packageVersionRequest := buildPackageVersionRequest(name, branchName)
   210  		// Retrive the package version using Artifactory
   211  		version, err = executersutils.GetPackageVersion(rtTargetRepo, packageVersionRequest, rtDetails)
   212  		if err != nil {
   213  			return
   214  		}
   215  	}
   216  	return filepath.Join(packageCachePath, name+"@"+version), nil
   217  
   218  }
   219  
   220  // buildPackageVersionRequest returns a string representing the version request to Artifactory.
   221  // The resulted string is in the following format: "<Package Name>/@V/<Branch Name>.info".
   222  // If a branch name is not given, the branch name will be replaced with the "latest" keyword.
   223  // ("<Package Name>/@V/latest.info").
   224  func buildPackageVersionRequest(name, branchName string) string {
   225  	packageVersionRequest := path.Join(name, "@v")
   226  	if branchName != "" {
   227  		// A branch name was given by the user
   228  		return path.Join(packageVersionRequest, branchName+".info")
   229  	}
   230  	// No version was given to "go get" command, so the latest version should be requested
   231  	return path.Join(packageVersionRequest, "latest.info")
   232  }
   233  
   234  // Returns true/false if info files should be included in the build info.
   235  func shouldIncludeInfoFiles(deployerServiceManager artifactory.ArtifactoryServicesManager, resolverServiceManager artifactory.ArtifactoryServicesManager) (bool, error) {
   236  	var artifactoryVersion string
   237  	var err error
   238  	if deployerServiceManager != nil {
   239  		artifactoryVersion, err = deployerServiceManager.GetConfig().GetServiceDetails().GetVersion()
   240  	} else {
   241  		artifactoryVersion, err = resolverServiceManager.GetConfig().GetServiceDetails().GetVersion()
   242  	}
   243  	if err != nil {
   244  		return false, err
   245  	}
   246  	version := version.NewVersion(artifactoryVersion)
   247  	includeInfoFiles := version.AtLeast(_go.ArtifactoryMinSupportedVersionForInfoFile)
   248  	return includeInfoFiles, nil
   249  }