github.com/SAP/jenkins-library@v1.362.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 utils := piperutils.Files{} 36 err := runAbapEnvironmentAssemblePackages(&config, telemetryData, &autils, &utils, &client, cpe) 37 if err != nil { 38 log.Entry().WithError(err).Fatal("step execution failed") 39 } 40 } 41 42 func runAbapEnvironmentAssemblePackages(config *abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, utils piperutils.FileUtils, client abapbuild.HTTPSendLoader, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) error { 43 connBuild := new(abapbuild.Connector) 44 if errConBuild := initAssemblePackagesConnection(connBuild, config, com, client); errConBuild != nil { 45 return errConBuild 46 } 47 48 addonDescriptor := new(abaputils.AddonDescriptor) 49 if err := addonDescriptor.InitFromJSONstring(config.AddonDescriptor); err != nil { 50 return errors.Wrap(err, "Reading AddonDescriptor failed [Make sure abapAddonAssemblyKit...CheckCVs|CheckPV|ReserveNextPackages steps have been run before]") 51 } 52 53 builds, err := executeBuilds(addonDescriptor, *connBuild, time.Duration(config.MaxRuntimeInMinutes)*time.Minute, time.Duration(config.PollIntervalsInMilliseconds)*time.Millisecond) 54 if err != nil { 55 return errors.Wrap(err, "Starting Builds for Repositories with reserved AAKaaS packages failed") 56 } 57 58 err = checkIfFailedAndPrintLogs(builds) 59 if err != nil { 60 return errors.Wrap(err, "Checking for failed Builds and Printing Build Logs failed") 61 } 62 63 _, 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 64 if err != nil { 65 return errors.Wrap(err, "Download of Build Artifact SAR_XML failed") 66 } 67 68 var filesToPublish []piperutils.Path 69 filesToPublish, err = downloadResultToFile(builds, "DELIVERY_LOGS.ZIP", true) 70 if err != nil { 71 return errors.Wrap(err, "Download of Build Artifact DELIVERY_LOGS.ZIP failed") 72 } 73 74 log.Entry().Infof("Publishing %v files", len(filesToPublish)) 75 piperutils.PersistReportsAndLinks("abapEnvironmentAssemblePackages", "", utils, filesToPublish, nil) 76 77 var reposBackToCPE []abaputils.Repository 78 for _, b := range builds { 79 reposBackToCPE = append(reposBackToCPE, b.repo) 80 } 81 addonDescriptor.SetRepositories(reposBackToCPE) 82 cpe.abap.addonDescriptor = addonDescriptor.AsJSONstring() 83 84 return nil 85 } 86 87 func executeBuilds(addonDescriptor *abaputils.AddonDescriptor, conn abapbuild.Connector, maxRuntimeInMinutes time.Duration, pollInterval time.Duration) ([]buildWithRepository, error) { 88 var builds []buildWithRepository 89 90 for _, repo := range addonDescriptor.Repositories { 91 92 buildRepo := buildWithRepository{ 93 build: abapbuild.Build{ 94 Connector: conn, 95 }, 96 repo: repo, 97 } 98 99 if repo.Status == "P" { 100 buildRepo.repo.InBuildScope = true 101 err := buildRepo.start(addonDescriptor) 102 if err != nil { 103 buildRepo.build.RunState = abapbuild.Failed 104 log.Entry().Error(err) 105 log.Entry().Info("Continueing with other builds (if any)") 106 } else { 107 err = buildRepo.waitToBeFinished(maxRuntimeInMinutes, pollInterval) 108 if err != nil { 109 buildRepo.build.RunState = abapbuild.Failed 110 log.Entry().Error(err) 111 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!") 112 } 113 } 114 } else { 115 log.Entry().Infof("Packages %s is in status '%s'. No need to run the assembly", repo.PackageName, repo.Status) 116 } 117 118 builds = append(builds, buildRepo) 119 } 120 return builds, nil 121 } 122 123 func (br *buildWithRepository) waitToBeFinished(maxRuntimeInMinutes time.Duration, pollInterval time.Duration) error { 124 timeout := time.After(maxRuntimeInMinutes) 125 ticker := time.Tick(pollInterval) 126 for { 127 select { 128 case <-timeout: 129 return errors.Errorf("Timed out: (max Runtime %v reached)", maxRuntimeInMinutes) 130 case <-ticker: 131 if err := br.build.Get(); err != nil { 132 return err 133 } 134 if !br.build.IsFinished() { 135 log.Entry().Infof("Assembly of %s is not yet finished, check again in %s", br.repo.PackageName, pollInterval) 136 } else { 137 return nil 138 } 139 } 140 } 141 } 142 143 func (br *buildWithRepository) start(addonDescriptor *abaputils.AddonDescriptor) error { 144 if br.repo.Name == "" || br.repo.Version == "" || br.repo.SpLevel == "" || br.repo.PackageType == "" || br.repo.PackageName == "" { 145 return errors.New("Parameters missing. Please provide software component name, version, sp-level, packagetype and packagename") 146 } 147 valuesInput := abapbuild.Values{ 148 Values: []abapbuild.Value{ 149 { 150 ValueID: "SWC", 151 Value: br.repo.Name, 152 }, 153 { 154 ValueID: "CVERS", 155 Value: br.repo.Name + "." + br.repo.Version + "." + br.repo.SpLevel, 156 }, 157 { 158 ValueID: "SEMANTIC_VERSION", 159 Value: br.repo.VersionYAML, 160 }, 161 { 162 ValueID: "PACKAGE_TYPE", 163 Value: br.repo.PackageType, 164 }, 165 { 166 ValueID: "PACKAGE_NAME_" + br.repo.PackageType, 167 Value: br.repo.PackageName, 168 }, 169 { 170 ValueID: "addonDescriptor", 171 Value: addonDescriptor.AsReducedJson(), 172 }, 173 }, 174 } 175 if br.repo.Namespace != "" { 176 valuesInput.Values = append(valuesInput.Values, 177 abapbuild.Value{ValueID: "NAMESPACE", 178 Value: br.repo.Namespace}) 179 } 180 if br.repo.UseClassicCTS { 181 valuesInput.Values = append(valuesInput.Values, 182 abapbuild.Value{ValueID: "useClassicCTS", 183 Value: "true"}) 184 } 185 if br.repo.PredecessorCommitID != "" { 186 valuesInput.Values = append(valuesInput.Values, 187 abapbuild.Value{ValueID: "PREVIOUS_DELIVERY_COMMIT", 188 Value: br.repo.PredecessorCommitID}) 189 } 190 if br.repo.CommitID != "" { 191 valuesInput.Values = append(valuesInput.Values, 192 abapbuild.Value{ValueID: "CURRENT_DELIVERY_COMMIT", 193 Value: br.repo.CommitID}) 194 } 195 if br.repo.Tag != "" { 196 valuesInput.Values = append(valuesInput.Values, abapbuild.Value{ValueID: "CURRENT_DELIVERY_TAG", Value: br.repo.Tag}) 197 } 198 if len(br.repo.Languages) > 0 { 199 valuesInput.Values = append(valuesInput.Values, 200 abapbuild.Value{ValueID: "SSDC_EXPORT_LANGUAGE_VECTOR", 201 Value: br.repo.GetAakAasLanguageVector()}) 202 } 203 if br.repo.AdditionalPiecelist != "" { 204 valuesInput.Values = append(valuesInput.Values, 205 abapbuild.Value{ValueID: "ADDITIONAL_PIECELIST", 206 Value: br.repo.AdditionalPiecelist}) 207 } 208 phase := "BUILD_" + br.repo.PackageType 209 log.Entry().Infof("Starting assembly of package %s", br.repo.PackageName) 210 return br.build.Start(phase, valuesInput) 211 } 212 213 func downloadResultToFile(builds []buildWithRepository, resultName string, publish bool) ([]piperutils.Path, error) { 214 envPath := filepath.Join(GeneralConfig.EnvRootPath, "abapBuild") 215 var filesToPublish []piperutils.Path 216 217 for i, b := range builds { 218 if b.repo.Status != "P" { 219 continue 220 } 221 buildResult, err := b.build.GetResult(resultName) 222 if err != nil { 223 return filesToPublish, err 224 } 225 var fileName string 226 if len(buildResult.AdditionalInfo) <= 255 { 227 fileName = buildResult.AdditionalInfo 228 } else { 229 fileName = buildResult.Name 230 } 231 downloadPath := filepath.Join(envPath, path.Base(fileName)) 232 log.Entry().Infof("Downloading %s file %s to %s", resultName, path.Base(fileName), downloadPath) 233 err = buildResult.Download(downloadPath) 234 if err != nil { 235 return filesToPublish, err 236 } 237 if resultName == "SAR_XML" { 238 builds[i].repo.SarXMLFilePath = downloadPath 239 } 240 if publish { 241 log.Entry().Infof("Add %s to be published", resultName) 242 filesToPublish = append(filesToPublish, piperutils.Path{Target: downloadPath, Name: resultName, Mandatory: true}) 243 } 244 } 245 return filesToPublish, nil 246 } 247 248 func checkIfFailedAndPrintLogs(builds []buildWithRepository) error { 249 var buildFailed bool = false 250 for i := range builds { 251 if builds[i].build.RunState == abapbuild.Failed { 252 log.Entry().Errorf("Assembly of %s failed", builds[i].repo.PackageName) 253 buildFailed = true 254 } 255 if builds[i].build.BuildID != "" { 256 if err := builds[i].build.PrintLogs(); err != nil { 257 return err 258 } 259 } 260 } 261 if buildFailed { 262 return errors.New("At least the assembly of one package failed") 263 } 264 return nil 265 } 266 267 func initAssemblePackagesConnection(conn *abapbuild.Connector, config *abapEnvironmentAssemblePackagesOptions, com abaputils.Communication, client abapbuild.HTTPSendLoader) error { 268 var connConfig abapbuild.ConnectorConfiguration 269 connConfig.CfAPIEndpoint = config.CfAPIEndpoint 270 connConfig.CfOrg = config.CfOrg 271 connConfig.CfSpace = config.CfSpace 272 connConfig.CfServiceInstance = config.CfServiceInstance 273 connConfig.CfServiceKeyName = config.CfServiceKeyName 274 connConfig.Host = config.Host 275 connConfig.Username = config.Username 276 connConfig.Password = config.Password 277 connConfig.AddonDescriptor = config.AddonDescriptor 278 connConfig.MaxRuntimeInMinutes = config.MaxRuntimeInMinutes 279 connConfig.CertificateNames = config.CertificateNames 280 281 err := conn.InitBuildFramework(connConfig, com, client) 282 if err != nil { 283 return errors.Wrap(err, "Connector initialization for communication with the ABAP system failed") 284 } 285 286 return nil 287 }