mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
9fdaf86856
* add useClassicCTS * add option additionalPiecelist * Update abapEnvironmentAssemblePackages.go
272 lines
9.1 KiB
Go
272 lines
9.1 KiB
Go
package cmd
|
|
|
|
import (
|
|
"path"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
|
|
"github.com/SAP/jenkins-library/pkg/abaputils"
|
|
"github.com/SAP/jenkins-library/pkg/command"
|
|
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type buildWithRepository struct {
|
|
build abapbuild.Build
|
|
repo abaputils.Repository
|
|
}
|
|
|
|
func abapEnvironmentAssemblePackages(config abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) {
|
|
// for command execution use Command
|
|
c := command.Command{}
|
|
// reroute command output to logging framework
|
|
c.Stdout(log.Writer())
|
|
c.Stderr(log.Writer())
|
|
|
|
var autils = abaputils.AbapUtils{
|
|
Exec: &c,
|
|
}
|
|
|
|
client := piperhttp.Client{}
|
|
err := runAbapEnvironmentAssemblePackages(&config, telemetryData, &autils, &client, cpe)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Fatal("step execution failed")
|
|
}
|
|
}
|
|
|
|
func runAbapEnvironmentAssemblePackages(config *abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client abapbuild.HTTPSendLoader, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) error {
|
|
connBuild := new(abapbuild.Connector)
|
|
if errConBuild := initAssemblePackagesConnection(connBuild, config, com, client); errConBuild != nil {
|
|
return errConBuild
|
|
}
|
|
|
|
addonDescriptor := new(abaputils.AddonDescriptor)
|
|
if err := addonDescriptor.InitFromJSONstring(config.AddonDescriptor); err != nil {
|
|
return errors.Wrap(err, "Reading AddonDescriptor failed [Make sure abapAddonAssemblyKit...CheckCVs|CheckPV|ReserveNextPackages steps have been run before]")
|
|
}
|
|
|
|
builds, err := executeBuilds(addonDescriptor.Repositories, *connBuild, time.Duration(config.MaxRuntimeInMinutes)*time.Minute, time.Duration(config.PollIntervalsInMilliseconds)*time.Millisecond)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Starting Builds for Repositories with reserved AAKaaS packages failed")
|
|
}
|
|
|
|
err = checkIfFailedAndPrintLogs(builds)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Checking for failed Builds and Printing Build Logs failed")
|
|
}
|
|
|
|
_, 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
|
|
if err != nil {
|
|
return errors.Wrap(err, "Download of Build Artifact SAR_XML failed")
|
|
}
|
|
|
|
var filesToPublish []piperutils.Path
|
|
filesToPublish, err = downloadResultToFile(builds, "DELIVERY_LOGS.ZIP", true)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Download of Build Artifact DELIVERY_LOGS.ZIP failed")
|
|
}
|
|
|
|
log.Entry().Infof("Publishing %v files", len(filesToPublish))
|
|
piperutils.PersistReportsAndLinks("abapEnvironmentAssemblePackages", "", filesToPublish, nil)
|
|
|
|
var reposBackToCPE []abaputils.Repository
|
|
for _, b := range builds {
|
|
reposBackToCPE = append(reposBackToCPE, b.repo)
|
|
}
|
|
addonDescriptor.SetRepositories(reposBackToCPE)
|
|
cpe.abap.addonDescriptor = addonDescriptor.AsJSONstring()
|
|
|
|
return nil
|
|
}
|
|
|
|
func executeBuilds(repos []abaputils.Repository, conn abapbuild.Connector, maxRuntimeInMinutes time.Duration, pollInterval time.Duration) ([]buildWithRepository, error) {
|
|
var builds []buildWithRepository
|
|
|
|
for _, repo := range repos {
|
|
|
|
buildRepo := buildWithRepository{
|
|
build: abapbuild.Build{
|
|
Connector: conn,
|
|
},
|
|
repo: repo,
|
|
}
|
|
|
|
if repo.Status == "P" {
|
|
buildRepo.repo.InBuildScope = true
|
|
err := buildRepo.start()
|
|
if err != nil {
|
|
buildRepo.build.RunState = abapbuild.Failed
|
|
log.Entry().Error(err)
|
|
log.Entry().Info("Continueing with other builds (if any)")
|
|
} else {
|
|
err = buildRepo.waitToBeFinished(maxRuntimeInMinutes, pollInterval)
|
|
if err != nil {
|
|
buildRepo.build.RunState = abapbuild.Failed
|
|
log.Entry().Error(err)
|
|
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!")
|
|
}
|
|
}
|
|
} else {
|
|
log.Entry().Infof("Packages %s is in status '%s'. No need to run the assembly", repo.PackageName, repo.Status)
|
|
}
|
|
|
|
builds = append(builds, buildRepo)
|
|
}
|
|
return builds, nil
|
|
}
|
|
|
|
func (br *buildWithRepository) waitToBeFinished(maxRuntimeInMinutes time.Duration, pollInterval time.Duration) error {
|
|
timeout := time.After(maxRuntimeInMinutes)
|
|
ticker := time.Tick(pollInterval)
|
|
for {
|
|
select {
|
|
case <-timeout:
|
|
return errors.Errorf("Timed out: (max Runtime %v reached)", maxRuntimeInMinutes)
|
|
case <-ticker:
|
|
br.build.Get()
|
|
if !br.build.IsFinished() {
|
|
log.Entry().Infof("Assembly of %s is not yet finished, check again in %s", br.repo.PackageName, pollInterval)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (br *buildWithRepository) start() error {
|
|
if br.repo.Name == "" || br.repo.Version == "" || br.repo.SpLevel == "" || br.repo.PackageType == "" || br.repo.PackageName == "" {
|
|
return errors.New("Parameters missing. Please provide software component name, version, sp-level, packagetype and packagename")
|
|
}
|
|
valuesInput := abapbuild.Values{
|
|
Values: []abapbuild.Value{
|
|
{
|
|
ValueID: "SWC",
|
|
Value: br.repo.Name,
|
|
},
|
|
{
|
|
ValueID: "CVERS",
|
|
Value: br.repo.Name + "." + br.repo.Version + "." + br.repo.SpLevel,
|
|
},
|
|
{
|
|
ValueID: "PACKAGE_TYPE",
|
|
Value: br.repo.PackageType,
|
|
},
|
|
{
|
|
ValueID: "PACKAGE_NAME_" + br.repo.PackageType,
|
|
Value: br.repo.PackageName,
|
|
},
|
|
},
|
|
}
|
|
if br.repo.Namespace != "" {
|
|
valuesInput.Values = append(valuesInput.Values,
|
|
abapbuild.Value{ValueID: "NAMESPACE",
|
|
Value: br.repo.Namespace})
|
|
}
|
|
if br.repo.UseClassicCTS {
|
|
valuesInput.Values = append(valuesInput.Values,
|
|
abapbuild.Value{ValueID: "useClassicCTS",
|
|
Value: "true"})
|
|
}
|
|
if br.repo.PredecessorCommitID != "" {
|
|
valuesInput.Values = append(valuesInput.Values,
|
|
abapbuild.Value{ValueID: "PREVIOUS_DELIVERY_COMMIT",
|
|
Value: br.repo.PredecessorCommitID})
|
|
}
|
|
if br.repo.CommitID != "" {
|
|
valuesInput.Values = append(valuesInput.Values,
|
|
abapbuild.Value{ValueID: "ACTUAL_DELIVERY_COMMIT",
|
|
Value: br.repo.CommitID})
|
|
}
|
|
if len(br.repo.Languages) > 0 {
|
|
valuesInput.Values = append(valuesInput.Values,
|
|
abapbuild.Value{ValueID: "SSDC_EXPORT_LANGUAGE_VECTOR",
|
|
Value: br.repo.GetAakAasLanguageVector()})
|
|
}
|
|
if br.repo.AdditionalPiecelist != "" {
|
|
valuesInput.Values = append(valuesInput.Values,
|
|
abapbuild.Value{ValueID: "ADDITIONAL_PIECELIST",
|
|
Value: br.repo.AdditionalPiecelist})
|
|
}
|
|
phase := "BUILD_" + br.repo.PackageType
|
|
log.Entry().Infof("Starting assembly of package %s", br.repo.PackageName)
|
|
return br.build.Start(phase, valuesInput)
|
|
}
|
|
|
|
func downloadResultToFile(builds []buildWithRepository, resultName string, publish bool) ([]piperutils.Path, error) {
|
|
envPath := filepath.Join(GeneralConfig.EnvRootPath, "abapBuild")
|
|
var filesToPublish []piperutils.Path
|
|
|
|
for i, b := range builds {
|
|
if b.repo.Status != "P" {
|
|
continue
|
|
}
|
|
buildResult, err := b.build.GetResult(resultName)
|
|
if err != nil {
|
|
return filesToPublish, err
|
|
}
|
|
var fileName string
|
|
if len(buildResult.AdditionalInfo) <= 255 {
|
|
fileName = buildResult.AdditionalInfo
|
|
} else {
|
|
fileName = buildResult.Name
|
|
}
|
|
downloadPath := filepath.Join(envPath, path.Base(fileName))
|
|
log.Entry().Infof("Downloading %s file %s to %s", resultName, path.Base(fileName), downloadPath)
|
|
err = buildResult.Download(downloadPath)
|
|
if err != nil {
|
|
return filesToPublish, err
|
|
}
|
|
if resultName == "SAR_XML" {
|
|
builds[i].repo.SarXMLFilePath = downloadPath
|
|
}
|
|
if publish {
|
|
log.Entry().Infof("Add %s to be published", resultName)
|
|
filesToPublish = append(filesToPublish, piperutils.Path{Target: downloadPath, Name: resultName, Mandatory: true})
|
|
}
|
|
}
|
|
return filesToPublish, nil
|
|
}
|
|
|
|
func checkIfFailedAndPrintLogs(builds []buildWithRepository) error {
|
|
var buildFailed bool = false
|
|
for i := range builds {
|
|
if builds[i].build.RunState == abapbuild.Failed {
|
|
log.Entry().Errorf("Assembly of %s failed", builds[i].repo.PackageName)
|
|
buildFailed = true
|
|
}
|
|
if builds[i].build.BuildID != "" {
|
|
builds[i].build.PrintLogs()
|
|
}
|
|
}
|
|
if buildFailed {
|
|
return errors.New("At least the assembly of one package failed")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func initAssemblePackagesConnection(conn *abapbuild.Connector, config *abapEnvironmentAssemblePackagesOptions, com abaputils.Communication, client abapbuild.HTTPSendLoader) error {
|
|
var connConfig abapbuild.ConnectorConfiguration
|
|
connConfig.CfAPIEndpoint = config.CfAPIEndpoint
|
|
connConfig.CfOrg = config.CfOrg
|
|
connConfig.CfSpace = config.CfSpace
|
|
connConfig.CfServiceInstance = config.CfServiceInstance
|
|
connConfig.CfServiceKeyName = config.CfServiceKeyName
|
|
connConfig.Host = config.Host
|
|
connConfig.Username = config.Username
|
|
connConfig.Password = config.Password
|
|
connConfig.AddonDescriptor = config.AddonDescriptor
|
|
connConfig.MaxRuntimeInMinutes = config.MaxRuntimeInMinutes
|
|
connConfig.CertificateNames = config.CertificateNames
|
|
|
|
err := conn.InitBuildFramework(connConfig, com, client)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Connector initialization for communication with the ABAP system failed")
|
|
}
|
|
|
|
return nil
|
|
}
|