2020-09-18 17:27:04 +02:00
package cmd
import (
"fmt"
"time"
"github.com/SAP/jenkins-library/pkg/abap/aakaas"
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/telemetry"
"github.com/pkg/errors"
)
func abapAddonAssemblyKitReserveNextPackages ( config abapAddonAssemblyKitReserveNextPackagesOptions , telemetryData * telemetry . CustomData , cpe * abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment ) {
// for command execution use Command
c := command . Command { }
// reroute command output to logging framework
c . Stdout ( log . Writer ( ) )
c . Stderr ( log . Writer ( ) )
client := piperhttp . Client { }
maxRuntimeInMinutes := time . Duration ( 5 * time . Minute )
pollIntervalsInSeconds := time . Duration ( 30 * time . Second )
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapAddonAssemblyKitReserveNextPackages ( & config , telemetryData , & client , cpe , maxRuntimeInMinutes , pollIntervalsInSeconds )
if err != nil {
log . Entry ( ) . WithError ( err ) . Fatal ( "step execution failed" )
}
}
func runAbapAddonAssemblyKitReserveNextPackages ( config * abapAddonAssemblyKitReserveNextPackagesOptions , telemetryData * telemetry . CustomData , client piperhttp . Sender ,
cpe * abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment , maxRuntimeInMinutes time . Duration , pollIntervalsInSeconds time . Duration ) error {
2021-11-04 23:04:00 +02:00
2020-09-18 17:27:04 +02:00
conn := new ( abapbuild . Connector )
2021-11-04 23:04:00 +02:00
if err := conn . InitAAKaaS ( config . AbapAddonAssemblyKitEndpoint , config . Username , config . Password , client ) ; err != nil {
return err
}
2020-09-18 17:27:04 +02:00
2021-11-04 23:04:00 +02:00
addonDescriptor := new ( abaputils . AddonDescriptor )
if err := addonDescriptor . InitFromJSONstring ( config . AddonDescriptor ) ; err != nil {
return errors . Wrap ( err , "Reading AddonDescriptor failed [Make sure abapAddonAssemblyKit...CheckCVs|CheckPV steps have been run before]" )
}
2020-09-18 17:27:04 +02:00
packagesWithRepos , err := reservePackages ( addonDescriptor . Repositories , * conn )
if err != nil {
return err
}
err = pollReserveNextPackages ( packagesWithRepos , maxRuntimeInMinutes , pollIntervalsInSeconds )
if err != nil {
return err
}
2021-11-04 23:04:00 +02:00
addonDescriptor . Repositories , err = checkAndCopyFieldsToRepositories ( packagesWithRepos )
if err != nil {
return err
}
2020-09-18 17:27:04 +02:00
log . Entry ( ) . Info ( "Writing package names, types, status, namespace and predecessorCommitID to CommonPipelineEnvironment" )
2021-11-04 23:04:00 +02:00
cpe . abap . addonDescriptor = addonDescriptor . AsJSONstring ( )
2020-09-18 17:27:04 +02:00
return nil
}
2021-11-04 23:04:00 +02:00
func checkAndCopyFieldsToRepositories ( pckgWR [ ] aakaas . PackageWithRepository ) ( [ ] abaputils . Repository , error ) {
2020-09-18 17:27:04 +02:00
var repos [ ] abaputils . Repository
2021-11-04 23:04:00 +02:00
log . Entry ( ) . Infof ( "%-30v | %-20v | %-6v | %-40v | %-40v" , "Software Component" , "Package" , "Status" , "CommitID (from addon.yml)" , "PredecessorCommitID (from AAKaaS)" )
2020-09-18 17:27:04 +02:00
for i := range pckgWR {
2021-11-04 23:04:00 +02:00
log . Entry ( ) . Infof ( "%-30v | %-20v | %-6v | %-40v | %-40v" , pckgWR [ i ] . Repo . Name , pckgWR [ i ] . Package . PackageName , pckgWR [ i ] . Package . Status , pckgWR [ i ] . Repo . CommitID , pckgWR [ i ] . Package . PredecessorCommitID )
if pckgWR [ i ] . Package . Status == aakaas . PackageStatusReleased {
//Ensure for Packages with Status R that CommitID of package = the one from addon.yml, beware of short commitID in addon.yml
addonYAMLcommitIDLength := len ( pckgWR [ i ] . Repo . CommitID )
if len ( pckgWR [ i ] . Package . CommitID ) < addonYAMLcommitIDLength {
return repos , errors . New ( "Provided CommitIDs have wrong length: " + pckgWR [ i ] . Repo . CommitID + "(addon.yml) longer than the one from AAKaaS " + pckgWR [ i ] . Package . CommitID )
}
packageCommitIDsubsting := pckgWR [ i ] . Package . CommitID [ 0 : addonYAMLcommitIDLength ]
if pckgWR [ i ] . Repo . CommitID != packageCommitIDsubsting {
log . Entry ( ) . Error ( "package " + pckgWR [ i ] . Package . PackageName + " was already build but with commit " + pckgWR [ i ] . Package . CommitID + ", not with " + pckgWR [ i ] . Repo . CommitID )
log . Entry ( ) . Error ( "If you want to build a new package make sure to increase the dotted-version-string in addon.yml" )
log . Entry ( ) . Error ( "If you do NOT want to build a new package enter the commitID " + pckgWR [ i ] . Package . CommitID + " for software component " + pckgWR [ i ] . Repo . Name + " in addon.yml" )
return repos , errors . New ( "commit of released package does not match with addon.yml" )
}
} else if pckgWR [ i ] . Package . PredecessorCommitID != "" {
//Check for newly reserved packages which are to be build that CommitID from addon.yml != PreviousCommitID [this will result in an error as no delta can be calculated]
addonYAMLcommitIDLength := len ( pckgWR [ i ] . Repo . CommitID )
if len ( pckgWR [ i ] . Package . PredecessorCommitID ) < addonYAMLcommitIDLength {
return repos , errors . New ( "Provided CommitIDs have wrong length: " + pckgWR [ i ] . Repo . CommitID + "(addon.yml) longer than the one from AAKaaS " + pckgWR [ i ] . Package . CommitID )
}
packagePredecessorCommitIDsubsting := pckgWR [ i ] . Package . PredecessorCommitID [ 0 : addonYAMLcommitIDLength ]
if pckgWR [ i ] . Repo . CommitID == packagePredecessorCommitIDsubsting {
return repos , errors . New ( "CommitID of package" + pckgWR [ i ] . Package . PackageName + "is the same as the on of the predecessor package. Make sure to change both the dotted-version-string AND the commitID in addon.yml" )
}
}
2020-09-18 17:27:04 +02:00
pckgWR [ i ] . Package . CopyFieldsToRepo ( & pckgWR [ i ] . Repo )
repos = append ( repos , pckgWR [ i ] . Repo )
}
2021-11-04 23:04:00 +02:00
return repos , nil
2020-09-18 17:27:04 +02:00
}
func pollReserveNextPackages ( pckgWR [ ] aakaas . PackageWithRepository , maxRuntimeInMinutes time . Duration , pollIntervalsInSeconds time . Duration ) error {
timeout := time . After ( maxRuntimeInMinutes )
ticker := time . Tick ( pollIntervalsInSeconds )
for {
select {
case <- timeout :
return errors . New ( "Timed out" )
case <- ticker :
var allFinished bool = true
for i := range pckgWR {
err := pckgWR [ i ] . Package . GetPackageAndNamespace ( )
// if there is an error, reservation is not yet finished
if err != nil {
log . Entry ( ) . Infof ( "Reservation of %s is not yet finished, check again in %s" , pckgWR [ i ] . Package . PackageName , pollIntervalsInSeconds )
allFinished = false
} else {
switch pckgWR [ i ] . Package . Status {
case aakaas . PackageStatusLocked :
return fmt . Errorf ( "Package %s has invalid status 'locked'" , pckgWR [ i ] . Package . PackageName )
case aakaas . PackageStatusCreationTriggered :
log . Entry ( ) . Infof ( "Reservation of %s is still running with status 'creation triggered', check again in %s" , pckgWR [ i ] . Package . PackageName , pollIntervalsInSeconds )
allFinished = false
case aakaas . PackageStatusPlanned :
2020-09-24 07:41:06 +02:00
log . Entry ( ) . Infof ( "Reservation of %s was successful with status 'planned'" , pckgWR [ i ] . Package . PackageName )
2020-09-18 17:27:04 +02:00
case aakaas . PackageStatusReleased :
log . Entry ( ) . Infof ( "Reservation of %s not needed, package is already in status 'released'" , pckgWR [ i ] . Package . PackageName )
default :
return fmt . Errorf ( "Package %s has unknown status '%s'" , pckgWR [ i ] . Package . PackageName , pckgWR [ i ] . Package . Status )
}
}
}
if allFinished {
2020-09-24 07:41:06 +02:00
log . Entry ( ) . Infof ( "Reservation of package(s) was successful" )
2020-09-18 17:27:04 +02:00
return nil
}
}
}
}
func reservePackages ( repositories [ ] abaputils . Repository , conn abapbuild . Connector ) ( [ ] aakaas . PackageWithRepository , error ) {
var packagesWithRepos [ ] aakaas . PackageWithRepository
for i := range repositories {
var p aakaas . Package
p . InitPackage ( repositories [ i ] , conn )
err := p . ReserveNext ( )
if err != nil {
return packagesWithRepos , err
}
pWR := aakaas . PackageWithRepository {
Package : p ,
Repo : repositories [ i ] ,
}
packagesWithRepos = append ( packagesWithRepos , pWR )
}
return packagesWithRepos , nil
}