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"
2021-12-09 13:54:18 +02:00
2020-09-18 17:27:04 +02:00
"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 ) {
2021-12-09 13:54:18 +02:00
utils := aakaas . NewAakBundleWithTime ( time . Duration ( config . MaxRuntimeInMinutes ) , time . Duration ( config . PollingIntervalInSeconds ) )
2020-09-18 17:27:04 +02:00
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
2021-12-09 13:54:18 +02:00
if err := runAbapAddonAssemblyKitReserveNextPackages ( & config , telemetryData , & utils , cpe ) ; err != nil {
2020-09-18 17:27:04 +02:00
log . Entry ( ) . WithError ( err ) . Fatal ( "step execution failed" )
}
}
2021-12-09 13:54:18 +02:00
func runAbapAddonAssemblyKitReserveNextPackages ( config * abapAddonAssemblyKitReserveNextPackagesOptions , telemetryData * telemetry . CustomData , utils * aakaas . AakUtils ,
cpe * abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment ) error {
2021-11-04 23:04:00 +02:00
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Info ( "╔═════════════════════════════════════════╗" )
log . Entry ( ) . Info ( "║ abapAddonAssemblyKitReserveNextPackages ║" )
log . Entry ( ) . Info ( "╚═════════════════════════════════════════╝" )
log . Entry ( ) . Infof ( "... initializing connection to AAKaaS @ %v" , config . AbapAddonAssemblyKitEndpoint )
2020-09-18 17:27:04 +02:00
conn := new ( abapbuild . Connector )
2021-12-09 13:54:18 +02:00
if err := conn . InitAAKaaS ( config . AbapAddonAssemblyKitEndpoint , config . Username , config . Password , * utils ) ; err != nil {
2021-11-04 23:04:00 +02:00
return err
}
2020-09-18 17:27:04 +02:00
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Info ( "... reading AddonDescriptor (Software Component, Version) from CommonPipelineEnvironment" )
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
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Info ( "╭────────────────────────────────┬──────────────────────╮" )
log . Entry ( ) . Info ( "│ Software Component │ Version │" )
log . Entry ( ) . Info ( "├────────────────────────────────┼──────────────────────┤" )
for i := range addonDescriptor . Repositories {
log . Entry ( ) . Infof ( "│ %-30v │ %-20v │" , addonDescriptor . Repositories [ i ] . Name , addonDescriptor . Repositories [ i ] . VersionYAML )
}
log . Entry ( ) . Info ( "╰────────────────────────────────┴──────────────────────╯" )
2020-09-18 17:27:04 +02:00
packagesWithRepos , err := reservePackages ( addonDescriptor . Repositories , * conn )
if err != nil {
return err
}
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Info ( "... checking for ongoing Reservations" )
2021-12-09 13:54:18 +02:00
if err = pollReserveNextPackages ( packagesWithRepos , utils ) ; err != nil {
2020-09-18 17:27:04 +02:00
return err
}
2021-11-04 23:04:00 +02:00
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Info ( "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓" )
log . Entry ( ) . Infof ( "┃ %-30v ┃ %-20v ┃ %-5v ┃ %-6v ┃ %-10v ┃ %-40v ┃ %-40v ┃" , "Software Component" , "Package Name" , "Type" , "Status" , "Namespace" , "CommitID (from addon.yml)" , "PredecessorCommitID (from AAKaaS)" )
log . Entry ( ) . Info ( "┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫" )
for i := range packagesWithRepos {
log . Entry ( ) . Infof ( "┃ %-30v ┃ %-20v ┃ %-5v ┃ %-6v ┃ %-10v ┃ %-40v ┃ %-40v ┃" , packagesWithRepos [ i ] . Repo . Name , packagesWithRepos [ i ] . Package . PackageName , packagesWithRepos [ i ] . Package . Type , packagesWithRepos [ i ] . Package . Status , packagesWithRepos [ i ] . Package . Namespace , packagesWithRepos [ i ] . Repo . CommitID , packagesWithRepos [ i ] . Package . PredecessorCommitID )
}
log . Entry ( ) . Info ( "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛" )
log . Entry ( ) . Info ( "... checking and processing provided and received data" )
if addonDescriptor . Repositories , err = checkAndCopyFieldsToRepositories ( packagesWithRepos ) ; err != nil {
2021-11-04 23:04:00 +02:00
return err
}
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Info ( "... writing AddonDescriptor (package name, type, status, namespace and predecessorCommitID) back 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
2022-09-01 08:53:41 +02:00
var checkFailure error = nil
2020-09-18 17:27:04 +02:00
for i := range pckgWR {
2022-09-01 08:53:41 +02:00
checkFailure = checkCommitID ( pckgWR , i , checkFailure )
2021-11-04 23:04:00 +02:00
2022-09-01 08:53:41 +02:00
pckgWR [ i ] . Package . CopyFieldsToRepo ( & pckgWR [ i ] . Repo )
repos = append ( repos , pckgWR [ i ] . Repo )
}
return repos , checkFailure
}
2021-11-04 23:04:00 +02:00
2022-09-01 08:53:41 +02:00
func checkCommitID ( pckgWR [ ] aakaas . PackageWithRepository , i int , checkFailure error ) error {
if ! pckgWR [ i ] . Repo . UseClassicCTS {
if pckgWR [ i ] . Package . Status == aakaas . PackageStatusReleased {
checkFailure = checkCommitIDSameAsGiven ( pckgWR , i , checkFailure )
} else if pckgWR [ i ] . Package . PredecessorCommitID != "" {
checkFailure = checkCommitIDNotSameAsPrevious ( pckgWR , i , checkFailure )
2021-11-04 23:04:00 +02:00
}
2022-09-01 08:53:41 +02:00
}
return checkFailure
}
2021-11-04 23:04:00 +02:00
2022-09-01 08:53:41 +02:00
func checkCommitIDSameAsGiven ( pckgWR [ ] aakaas . PackageWithRepository , i int , checkFailure error ) error {
//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 {
checkFailure = errors . New ( "Provided CommitIDs have wrong length: " + pckgWR [ i ] . Repo . CommitID + "(addon.yml) longer than the one from AAKaaS " + pckgWR [ i ] . Package . CommitID )
log . Entry ( ) . WithError ( checkFailure ) . Error ( " => Check failure: to be corrected in addon.yml prior next execution" )
} else {
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 - current value: " + pckgWR [ i ] . Package . VersionYAML )
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" )
checkFailure = errors . New ( "commit of already released package does not match with addon.yml" )
log . Entry ( ) . WithError ( checkFailure ) . Error ( " => Check failure: to be corrected in addon.yml prior next execution" )
}
}
return checkFailure
}
func checkCommitIDNotSameAsPrevious ( pckgWR [ ] aakaas . PackageWithRepository , i int , checkFailure error ) error {
//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 {
checkFailure = errors . New ( "Provided CommitIDs have wrong length: " + pckgWR [ i ] . Repo . CommitID + "(addon.yml) longer than the one from AAKaaS " + pckgWR [ i ] . Package . CommitID )
log . Entry ( ) . WithError ( checkFailure ) . Error ( " => Check failure: to be corrected in addon.yml prior next execution" )
} else {
packagePredecessorCommitIDsubsting := pckgWR [ i ] . Package . PredecessorCommitID [ 0 : addonYAMLcommitIDLength ]
if pckgWR [ i ] . Repo . CommitID == packagePredecessorCommitIDsubsting {
checkFailure = errors . New ( "CommitID of package " + pckgWR [ i ] . Package . PackageName + " is the same as the one of the predecessor package. Make sure to change both the dotted-version-string AND the commitID in addon.yml" )
log . Entry ( ) . WithError ( checkFailure ) . Error ( " => Check failure: to be corrected in addon.yml prior next execution" )
}
2020-09-18 17:27:04 +02:00
}
2022-09-01 08:53:41 +02:00
return checkFailure
2020-09-18 17:27:04 +02:00
}
2021-12-09 13:54:18 +02:00
func pollReserveNextPackages ( pckgWR [ ] aakaas . PackageWithRepository , utils * aakaas . AakUtils ) error {
pollingInterval := ( * utils ) . GetPollingInterval ( )
timeout := time . After ( ( * utils ) . GetMaxRuntime ( ) )
ticker := time . Tick ( pollingInterval )
2020-09-18 17:27:04 +02:00
for {
select {
case <- timeout :
return errors . New ( "Timed out" )
case <- ticker :
var allFinished bool = true
for i := range pckgWR {
2022-09-01 08:53:41 +02:00
if pckgWR [ i ] . Package . Status == aakaas . PackageStatusReleased {
continue
}
2020-09-18 17:27:04 +02:00
err := pckgWR [ i ] . Package . GetPackageAndNamespace ( )
// if there is an error, reservation is not yet finished
if err != nil {
2021-12-09 13:54:18 +02:00
log . Entry ( ) . Infof ( "Reservation of %s is not yet finished, check again in %s" , pckgWR [ i ] . Package . PackageName , pollingInterval )
2020-09-18 17:27:04 +02:00
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 :
2021-12-09 13:54:18 +02:00
log . Entry ( ) . Infof ( "Reservation of %s is still running with status 'creation triggered', check again in %s" , pckgWR [ i ] . Package . PackageName , pollingInterval )
2020-09-18 17:27:04 +02:00
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 {
2022-09-01 08:53:41 +02:00
log . Entry ( ) . Infof ( " => Reservations of package(s) finished successfully" )
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
}