2020-08-27 07:54:03 +02:00
package cmd
import (
"path"
"path/filepath"
"time"
2020-09-30 16:40:36 +02:00
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
2020-08-27 07:54:03 +02:00
"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"
2021-03-11 12:55:12 +02:00
"github.com/SAP/jenkins-library/pkg/piperutils"
2020-08-27 07:54:03 +02:00
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
2020-09-30 16:40:36 +02:00
type buildWithRepository struct {
build abapbuild . Build
repo abaputils . Repository
}
2020-08-27 07:54:03 +02:00
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" )
}
}
2021-03-01 14:51:44 +02:00
func runAbapEnvironmentAssemblePackages ( config * abapEnvironmentAssemblePackagesOptions , telemetryData * telemetry . CustomData , com abaputils . Communication , client abapbuild . HTTPSendLoader , cpe * abapEnvironmentAssemblePackagesCommonPipelineEnvironment ) error {
2021-11-02 12:00:01 +02:00
connBuild := new ( abapbuild . Connector )
if errConBuild := initAssemblePackagesConnection ( connBuild , config , com , client ) ; errConBuild != nil {
return errConBuild
2020-08-27 07:54:03 +02:00
}
2021-03-01 14:51:44 +02:00
2021-11-02 12:00:01 +02:00
addonDescriptor := new ( abaputils . AddonDescriptor )
if err := addonDescriptor . InitFromJSONstring ( config . AddonDescriptor ) ; err != nil {
2021-03-01 14:51:44 +02:00
return errors . Wrap ( err , "Reading AddonDescriptor failed [Make sure abapAddonAssemblyKit...CheckCVs|CheckPV|ReserveNextPackages steps have been run before]" )
2020-09-30 16:40:36 +02:00
}
2021-03-01 14:51:44 +02:00
2021-11-02 12:00:01 +02:00
builds , err := executeBuilds ( addonDescriptor . Repositories , * connBuild , time . Duration ( config . MaxRuntimeInMinutes ) * time . Minute , time . Duration ( config . PollIntervalsInMilliseconds ) * time . Millisecond )
2020-08-27 07:54:03 +02:00
if err != nil {
2021-03-11 12:55:12 +02:00
return errors . Wrap ( err , "Starting Builds for Repositories with reserved AAKaaS packages failed" )
2020-08-27 07:54:03 +02:00
}
2021-03-01 14:51:44 +02:00
2020-08-27 07:54:03 +02:00
err = checkIfFailedAndPrintLogs ( builds )
if err != nil {
2021-03-11 12:55:12 +02:00
return errors . Wrap ( err , "Checking for failed Builds and Printing Build Logs failed" )
}
2021-11-02 12:00:01 +02:00
_ , 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
2021-03-11 12:55:12 +02:00
if err != nil {
return errors . Wrap ( err , "Download of Build Artifact SAR_XML failed" )
2020-08-27 07:54:03 +02:00
}
2021-03-11 12:55:12 +02:00
2021-11-02 12:00:01 +02:00
var filesToPublish [ ] piperutils . Path
filesToPublish , err = downloadResultToFile ( builds , "DELIVERY_LOGS.ZIP" , true )
2020-08-27 07:54:03 +02:00
if err != nil {
2021-11-02 12:00:01 +02:00
return errors . Wrap ( err , "Download of Build Artifact DELIVERY_LOGS.ZIP failed" )
2020-08-27 07:54:03 +02:00
}
2021-03-11 12:55:12 +02:00
2021-11-02 12:00:01 +02:00
log . Entry ( ) . Infof ( "Publishing %v files" , len ( filesToPublish ) )
2021-03-11 12:55:12 +02:00
piperutils . PersistReportsAndLinks ( "abapEnvironmentAssemblePackages" , "" , filesToPublish , nil )
var reposBackToCPE [ ] abaputils . Repository
for _ , b := range builds {
2020-08-27 07:54:03 +02:00
reposBackToCPE = append ( reposBackToCPE , b . repo )
}
2021-11-02 12:00:01 +02:00
addonDescriptor . SetRepositories ( reposBackToCPE )
cpe . abap . addonDescriptor = addonDescriptor . AsJSONstring ( )
2020-08-27 07:54:03 +02:00
return nil
}
2021-10-28 11:01:16 +02:00
func executeBuilds ( repos [ ] abaputils . Repository , conn abapbuild . Connector , maxRuntimeInMinutes time . Duration , pollInterval time . Duration ) ( [ ] buildWithRepository , error ) {
2020-08-27 07:54:03 +02:00
var builds [ ] buildWithRepository
2021-03-11 12:55:12 +02:00
2020-08-27 07:54:03 +02:00
for _ , repo := range repos {
2021-03-11 12:55:12 +02:00
2020-08-27 07:54:03 +02:00
buildRepo := buildWithRepository {
2021-03-11 12:55:12 +02:00
build : abapbuild . Build {
Connector : conn ,
} ,
repo : repo ,
2020-08-27 07:54:03 +02:00
}
2021-03-11 12:55:12 +02:00
2020-08-27 07:54:03 +02:00
if repo . Status == "P" {
2021-10-28 11:01:16 +02:00
buildRepo . repo . InBuildScope = true
2020-08-27 07:54:03 +02:00
err := buildRepo . start ( )
if err != nil {
2021-03-11 12:55:12 +02:00
buildRepo . build . RunState = abapbuild . Failed
log . Entry ( ) . Error ( err )
log . Entry ( ) . Info ( "Continueing with other builds (if any)" )
} else {
2021-10-28 11:01:16 +02:00
err = buildRepo . waitToBeFinished ( maxRuntimeInMinutes , pollInterval )
2021-03-11 12:55:12 +02:00
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!" )
}
2020-08-27 07:54:03 +02:00
}
} else {
2020-09-30 16:40:36 +02:00
log . Entry ( ) . Infof ( "Packages %s is in status '%s'. No need to run the assembly" , repo . PackageName , repo . Status )
2020-08-27 07:54:03 +02:00
}
2020-11-17 11:26:15 +02:00
2021-03-11 12:55:12 +02:00
builds = append ( builds , buildRepo )
2020-08-27 07:54:03 +02:00
}
2021-03-11 12:55:12 +02:00
return builds , nil
2020-08-27 07:54:03 +02:00
}
2021-10-28 11:01:16 +02:00
func ( br * buildWithRepository ) waitToBeFinished ( maxRuntimeInMinutes time . Duration , pollInterval time . Duration ) error {
2020-09-30 16:40:36 +02:00
timeout := time . After ( maxRuntimeInMinutes )
2021-10-28 11:01:16 +02:00
ticker := time . Tick ( pollInterval )
2020-08-27 07:54:03 +02:00
for {
select {
case <- timeout :
2021-03-01 14:51:44 +02:00
return errors . Errorf ( "Timed out: (max Runtime %v reached)" , maxRuntimeInMinutes )
2020-08-27 07:54:03 +02:00
case <- ticker :
2022-07-06 14:29:04 +02:00
if err := br . build . Get ( ) ; err != nil {
return err
}
2021-03-11 12:55:12 +02:00
if ! br . build . IsFinished ( ) {
2021-10-28 11:01:16 +02:00
log . Entry ( ) . Infof ( "Assembly of %s is not yet finished, check again in %s" , br . repo . PackageName , pollInterval )
2021-03-11 12:55:12 +02:00
} else {
2020-08-27 07:54:03 +02:00
return nil
}
}
}
}
2021-03-11 12:55:12 +02:00
func ( br * buildWithRepository ) start ( ) error {
2022-04-12 14:39:42 +02:00
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" )
2020-08-27 07:54:03 +02:00
}
2020-09-30 16:40:36 +02:00
valuesInput := abapbuild . Values {
Values : [ ] abapbuild . Value {
2020-08-27 07:54:03 +02:00
{
ValueID : "SWC" ,
2021-03-11 12:55:12 +02:00
Value : br . repo . Name ,
2020-08-27 07:54:03 +02:00
} ,
{
ValueID : "CVERS" ,
2021-03-11 12:55:12 +02:00
Value : br . repo . Name + "." + br . repo . Version + "." + br . repo . SpLevel ,
2020-08-27 07:54:03 +02:00
} ,
2021-10-05 15:20:13 +02:00
{
ValueID : "PACKAGE_TYPE" ,
Value : br . repo . PackageType ,
} ,
2020-08-27 07:54:03 +02:00
{
2021-03-11 12:55:12 +02:00
ValueID : "PACKAGE_NAME_" + br . repo . PackageType ,
Value : br . repo . PackageName ,
2020-08-27 07:54:03 +02:00
} ,
} ,
}
2022-04-12 14:39:42 +02:00
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" } )
}
2021-03-11 12:55:12 +02:00
if br . repo . PredecessorCommitID != "" {
2020-08-27 07:54:03 +02:00
valuesInput . Values = append ( valuesInput . Values ,
2020-09-30 16:40:36 +02:00
abapbuild . Value { ValueID : "PREVIOUS_DELIVERY_COMMIT" ,
2021-03-11 12:55:12 +02:00
Value : br . repo . PredecessorCommitID } )
}
if br . repo . CommitID != "" {
valuesInput . Values = append ( valuesInput . Values ,
abapbuild . Value { ValueID : "ACTUAL_DELIVERY_COMMIT" ,
Value : br . repo . CommitID } )
}
2021-03-15 21:24:43 +02:00
if len ( br . repo . Languages ) > 0 {
valuesInput . Values = append ( valuesInput . Values ,
abapbuild . Value { ValueID : "SSDC_EXPORT_LANGUAGE_VECTOR" ,
Value : br . repo . GetAakAasLanguageVector ( ) } )
}
2022-04-12 16:00:17 +02:00
if br . repo . AdditionalPiecelist != "" {
valuesInput . Values = append ( valuesInput . Values ,
abapbuild . Value { ValueID : "ADDITIONAL_PIECELIST" ,
Value : br . repo . AdditionalPiecelist } )
}
2021-03-11 12:55:12 +02:00
phase := "BUILD_" + br . repo . PackageType
log . Entry ( ) . Infof ( "Starting assembly of package %s" , br . repo . PackageName )
return br . build . Start ( phase , valuesInput )
}
2021-11-02 12:00:01 +02:00
func downloadResultToFile ( builds [ ] buildWithRepository , resultName string , publish bool ) ( [ ] piperutils . Path , error ) {
envPath := filepath . Join ( GeneralConfig . EnvRootPath , "abapBuild" )
var filesToPublish [ ] piperutils . Path
2021-03-11 12:55:12 +02:00
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
}
2021-11-02 12:00:01 +02:00
if publish {
log . Entry ( ) . Infof ( "Add %s to be published" , resultName )
filesToPublish = append ( filesToPublish , piperutils . Path { Target : downloadPath , Name : resultName , Mandatory : true } )
}
2020-08-27 07:54:03 +02:00
}
2021-03-11 12:55:12 +02:00
return filesToPublish , nil
2020-08-27 07:54:03 +02:00
}
2021-03-01 14:51:44 +02:00
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
}
2022-04-12 14:39:42 +02:00
if builds [ i ] . build . BuildID != "" {
2022-07-06 14:29:04 +02:00
if err := builds [ i ] . build . PrintLogs ( ) ; err != nil {
return err
}
2022-04-12 14:39:42 +02:00
}
2021-03-01 14:51:44 +02:00
}
if buildFailed {
return errors . New ( "At least the assembly of one package failed" )
}
return nil
}
2021-11-02 12:00:01 +02:00
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
2022-04-12 14:39:42 +02:00
connConfig . CertificateNames = config . CertificateNames
2021-11-02 12:00:01 +02:00
err := conn . InitBuildFramework ( connConfig , com , client )
if err != nil {
return errors . Wrap ( err , "Connector initialization for communication with the ABAP system failed" )
}
return nil
}