github.com/xgoffin/jenkins-library@v1.154.0/cmd/abapEnvironmentAssemblePackages.go (about) 1 package cmd 2 3 import ( 4 "path" 5 "path/filepath" 6 "time" 7 8 abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" 9 "github.com/SAP/jenkins-library/pkg/abaputils" 10 "github.com/SAP/jenkins-library/pkg/command" 11 piperhttp "github.com/SAP/jenkins-library/pkg/http" 12 "github.com/SAP/jenkins-library/pkg/log" 13 "github.com/SAP/jenkins-library/pkg/piperutils" 14 "github.com/SAP/jenkins-library/pkg/telemetry" 15 "github.com/pkg/errors" 16 ) 17 18 type buildWithRepository struct { 19 build abapbuild.Build 20 repo abaputils.Repository 21 } 22 23 func abapEnvironmentAssemblePackages(config abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) { 24 // for command execution use Command 25 c := command.Command{} 26 // reroute command output to logging framework 27 c.Stdout(log.Writer()) 28 c.Stderr(log.Writer()) 29 30 var autils = abaputils.AbapUtils{ 31 Exec: &c, 32 } 33 34 client := piperhttp.Client{} 35 err := runAbapEnvironmentAssemblePackages(&config, telemetryData, &autils, &client, cpe) 36 if err != nil { 37 log.Entry().WithError(err).Fatal("step execution failed") 38 } 39 } 40 41 func runAbapEnvironmentAssemblePackages(config *abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client abapbuild.HTTPSendLoader, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) error { 42 connBuild := new(abapbuild.Connector) 43 if errConBuild := initAssemblePackagesConnection(connBuild, config, com, client); errConBuild != nil { 44 return errConBuild 45 } 46 47 addonDescriptor := new(abaputils.AddonDescriptor) 48 if err := addonDescriptor.InitFromJSONstring(config.AddonDescriptor); err != nil { 49 return errors.Wrap(err, "Reading AddonDescriptor failed [Make sure abapAddonAssemblyKit...CheckCVs|CheckPV|ReserveNextPackages steps have been run before]") 50 } 51 52 builds, err := executeBuilds(addonDescriptor.Repositories, *connBuild, time.Duration(config.MaxRuntimeInMinutes)*time.Minute, time.Duration(config.PollIntervalsInMilliseconds)*time.Millisecond) 53 if err != nil { 54 return errors.Wrap(err, "Starting Builds for Repositories with reserved AAKaaS packages failed") 55 } 56 57 err = checkIfFailedAndPrintLogs(builds) 58 if err != nil { 59 return errors.Wrap(err, "Checking for failed Builds and Printing Build Logs failed") 60 } 61 62 _, err = downloadResultToFile(builds, "SAR_XML", false) //File is present in ABAP build system and uploaded to AAKaaS, no need to fill up jenkins with it 63 if err != nil { 64 return errors.Wrap(err, "Download of Build Artifact SAR_XML failed") 65 } 66 67 var filesToPublish []piperutils.Path 68 filesToPublish, err = downloadResultToFile(builds, "DELIVERY_LOGS.ZIP", true) 69 if err != nil { 70 return errors.Wrap(err, "Download of Build Artifact DELIVERY_LOGS.ZIP failed") 71 } 72 73 log.Entry().Infof("Publishing %v files", len(filesToPublish)) 74 piperutils.PersistReportsAndLinks("abapEnvironmentAssemblePackages", "", filesToPublish, nil) 75 76 var reposBackToCPE []abaputils.Repository 77 for _, b := range builds { 78 reposBackToCPE = append(reposBackToCPE, b.repo) 79 } 80 addonDescriptor.SetRepositories(reposBackToCPE) 81 cpe.abap.addonDescriptor = addonDescriptor.AsJSONstring() 82 83 return nil 84 } 85 86 func executeBuilds(repos []abaputils.Repository, conn abapbuild.Connector, maxRuntimeInMinutes time.Duration, pollInterval time.Duration) ([]buildWithRepository, error) { 87 var builds []buildWithRepository 88 89 for _, repo := range repos { 90 91 buildRepo := buildWithRepository{ 92 build: abapbuild.Build{ 93 Connector: conn, 94 }, 95 repo: repo, 96 } 97 98 if repo.Status == "P" { 99 buildRepo.repo.InBuildScope = true 100 err := buildRepo.start() 101 if err != nil { 102 buildRepo.build.RunState = abapbuild.Failed 103 log.Entry().Error(err) 104 log.Entry().Info("Continueing with other builds (if any)") 105 } else { 106 err = buildRepo.waitToBeFinished(maxRuntimeInMinutes, pollInterval) 107 if err != nil { 108 buildRepo.build.RunState = abapbuild.Failed 109 log.Entry().Error(err) 110 log.Entry().Error("Continuing with other builds (if any) but keep in Mind that even if this build finishes beyond timeout the result is not trustworthy due to possible side effects!") 111 } 112 } 113 } else { 114 log.Entry().Infof("Packages %s is in status '%s'. No need to run the assembly", repo.PackageName, repo.Status) 115 } 116 117 builds = append(builds, buildRepo) 118 } 119 return builds, nil 120 } 121 122 func (br *buildWithRepository) waitToBeFinished(maxRuntimeInMinutes time.Duration, pollInterval time.Duration) error { 123 timeout := time.After(maxRuntimeInMinutes) 124 ticker := time.Tick(pollInterval) 125 for { 126 select { 127 case <-timeout: 128 return errors.Errorf("Timed out: (max Runtime %v reached)", maxRuntimeInMinutes) 129 case <-ticker: 130 br.build.Get() 131 if !br.build.IsFinished() { 132 log.Entry().Infof("Assembly of %s is not yet finished, check again in %s", br.repo.PackageName, pollInterval) 133 } else { 134 return nil 135 } 136 } 137 } 138 } 139 140 func (br *buildWithRepository) start() error { 141 if br.repo.Name == "" || br.repo.Version == "" || br.repo.SpLevel == "" || br.repo.Namespace == "" || br.repo.PackageType == "" || br.repo.PackageName == "" { 142 return errors.New("Parameters missing. Please provide software component name, version, sp-level, namespace, packagetype and packagename") 143 } 144 valuesInput := abapbuild.Values{ 145 Values: []abapbuild.Value{ 146 { 147 ValueID: "SWC", 148 Value: br.repo.Name, 149 }, 150 { 151 ValueID: "CVERS", 152 Value: br.repo.Name + "." + br.repo.Version + "." + br.repo.SpLevel, 153 }, 154 { 155 ValueID: "NAMESPACE", 156 Value: br.repo.Namespace, 157 }, 158 { 159 ValueID: "PACKAGE_TYPE", 160 Value: br.repo.PackageType, 161 }, 162 { 163 ValueID: "PACKAGE_NAME_" + br.repo.PackageType, 164 Value: br.repo.PackageName, 165 }, 166 }, 167 } 168 if br.repo.PredecessorCommitID != "" { 169 valuesInput.Values = append(valuesInput.Values, 170 abapbuild.Value{ValueID: "PREVIOUS_DELIVERY_COMMIT", 171 Value: br.repo.PredecessorCommitID}) 172 } 173 if br.repo.CommitID != "" { 174 valuesInput.Values = append(valuesInput.Values, 175 abapbuild.Value{ValueID: "ACTUAL_DELIVERY_COMMIT", 176 Value: br.repo.CommitID}) 177 } 178 if len(br.repo.Languages) > 0 { 179 valuesInput.Values = append(valuesInput.Values, 180 abapbuild.Value{ValueID: "SSDC_EXPORT_LANGUAGE_VECTOR", 181 Value: br.repo.GetAakAasLanguageVector()}) 182 } 183 184 phase := "BUILD_" + br.repo.PackageType 185 log.Entry().Infof("Starting assembly of package %s", br.repo.PackageName) 186 return br.build.Start(phase, valuesInput) 187 } 188 189 func downloadResultToFile(builds []buildWithRepository, resultName string, publish bool) ([]piperutils.Path, error) { 190 envPath := filepath.Join(GeneralConfig.EnvRootPath, "abapBuild") 191 var filesToPublish []piperutils.Path 192 193 for i, b := range builds { 194 if b.repo.Status != "P" { 195 continue 196 } 197 buildResult, err := b.build.GetResult(resultName) 198 if err != nil { 199 return filesToPublish, err 200 } 201 var fileName string 202 if len(buildResult.AdditionalInfo) <= 255 { 203 fileName = buildResult.AdditionalInfo 204 } else { 205 fileName = buildResult.Name 206 } 207 downloadPath := filepath.Join(envPath, path.Base(fileName)) 208 log.Entry().Infof("Downloading %s file %s to %s", resultName, path.Base(fileName), downloadPath) 209 err = buildResult.Download(downloadPath) 210 if err != nil { 211 return filesToPublish, err 212 } 213 if resultName == "SAR_XML" { 214 builds[i].repo.SarXMLFilePath = downloadPath 215 } 216 if publish { 217 log.Entry().Infof("Add %s to be published", resultName) 218 filesToPublish = append(filesToPublish, piperutils.Path{Target: downloadPath, Name: resultName, Mandatory: true}) 219 } 220 } 221 return filesToPublish, nil 222 } 223 224 func checkIfFailedAndPrintLogs(builds []buildWithRepository) error { 225 var buildFailed bool = false 226 for i := range builds { 227 if builds[i].build.RunState == abapbuild.Failed { 228 log.Entry().Errorf("Assembly of %s failed", builds[i].repo.PackageName) 229 buildFailed = true 230 } 231 builds[i].build.PrintLogs() 232 } 233 if buildFailed { 234 return errors.New("At least the assembly of one package failed") 235 } 236 return nil 237 } 238 239 func initAssemblePackagesConnection(conn *abapbuild.Connector, config *abapEnvironmentAssemblePackagesOptions, com abaputils.Communication, client abapbuild.HTTPSendLoader) error { 240 var connConfig abapbuild.ConnectorConfiguration 241 connConfig.CfAPIEndpoint = config.CfAPIEndpoint 242 connConfig.CfOrg = config.CfOrg 243 connConfig.CfSpace = config.CfSpace 244 connConfig.CfServiceInstance = config.CfServiceInstance 245 connConfig.CfServiceKeyName = config.CfServiceKeyName 246 connConfig.Host = config.Host 247 connConfig.Username = config.Username 248 connConfig.Password = config.Password 249 connConfig.AddonDescriptor = config.AddonDescriptor 250 connConfig.MaxRuntimeInMinutes = config.MaxRuntimeInMinutes 251 252 err := conn.InitBuildFramework(connConfig, com, client) 253 if err != nil { 254 return errors.Wrap(err, "Connector initialization for communication with the ABAP system failed") 255 } 256 257 return nil 258 }