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  }