mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
271 lines
8.8 KiB
Go
271 lines
8.8 KiB
Go
|
package cmd
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"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 abapEnvironmentBuildUtils interface {
|
||
|
command.ExecRunner
|
||
|
abaputils.Communication
|
||
|
abapbuild.Publish
|
||
|
abapbuild.HTTPSendLoader
|
||
|
getMaxRuntime() time.Duration
|
||
|
getPollingIntervall() time.Duration
|
||
|
}
|
||
|
|
||
|
type abapEnvironmentBuildUtilsBundle struct {
|
||
|
*command.Command
|
||
|
*piperhttp.Client
|
||
|
*abaputils.AbapUtils
|
||
|
maxRuntime time.Duration
|
||
|
pollingIntervall time.Duration
|
||
|
}
|
||
|
|
||
|
func (aEBUB *abapEnvironmentBuildUtilsBundle) getMaxRuntime() time.Duration {
|
||
|
return aEBUB.maxRuntime
|
||
|
}
|
||
|
|
||
|
func (aEBUB *abapEnvironmentBuildUtilsBundle) getPollingIntervall() time.Duration {
|
||
|
return aEBUB.pollingIntervall
|
||
|
}
|
||
|
|
||
|
func (aEBUB *abapEnvironmentBuildUtilsBundle) PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
|
||
|
abapbuild.PersistReportsAndLinks(stepName, workspace, reports, links)
|
||
|
}
|
||
|
|
||
|
func newAbapEnvironmentBuildUtils(maxRuntime time.Duration, pollingIntervall time.Duration) abapEnvironmentBuildUtils {
|
||
|
utils := abapEnvironmentBuildUtilsBundle{
|
||
|
Command: &command.Command{},
|
||
|
Client: &piperhttp.Client{},
|
||
|
AbapUtils: &abaputils.AbapUtils{
|
||
|
Exec: &command.Command{},
|
||
|
},
|
||
|
maxRuntime: maxRuntime * time.Minute,
|
||
|
pollingIntervall: pollingIntervall * time.Second,
|
||
|
}
|
||
|
// Reroute command output to logging framework
|
||
|
utils.Stdout(log.Writer())
|
||
|
utils.Stderr(log.Writer())
|
||
|
return &utils
|
||
|
}
|
||
|
|
||
|
func abapEnvironmentBuild(config abapEnvironmentBuildOptions, telemetryData *telemetry.CustomData, cpe *abapEnvironmentBuildCommonPipelineEnvironment) {
|
||
|
utils := newAbapEnvironmentBuildUtils(time.Duration(config.MaxRuntimeInMinutes), time.Duration(config.PollingIntervallInSeconds))
|
||
|
if err := runAbapEnvironmentBuild(&config, telemetryData, &utils, cpe); err != nil {
|
||
|
log.Entry().WithError(err).Fatal("step execution failed")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func runAbapEnvironmentBuild(config *abapEnvironmentBuildOptions, telemetryData *telemetry.CustomData, utils *abapEnvironmentBuildUtils, cpe *abapEnvironmentBuildCommonPipelineEnvironment) error {
|
||
|
values, err := generateValues(config)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "Generating the values from config failed")
|
||
|
}
|
||
|
conn := new(abapbuild.Connector)
|
||
|
if err := initConnection(conn, config, utils); err != nil {
|
||
|
return errors.Wrap(err, "Connector initialization for communication with the ABAP system failed")
|
||
|
}
|
||
|
finalValues, err := runBuild(conn, config, utils, values)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "Error during execution of build framework")
|
||
|
}
|
||
|
cpe.abap.buildValues = finalValues
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func initConnection(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils *abapEnvironmentBuildUtils) 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.MaxRuntimeInMinutes = config.MaxRuntimeInMinutes
|
||
|
connConfig.CertificateNames = config.CertificateNames
|
||
|
|
||
|
if err := conn.InitBuildFramework(connConfig, *utils, *utils); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
conn.MaxRuntime = (*utils).getMaxRuntime()
|
||
|
conn.PollingInterval = (*utils).getPollingIntervall()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// ***********************************Run Build***************************************************************
|
||
|
func runBuild(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils *abapEnvironmentBuildUtils, values abapbuild.Values) (string, error) {
|
||
|
build := myBuild{
|
||
|
Build: abapbuild.Build{
|
||
|
Connector: *conn,
|
||
|
},
|
||
|
abapEnvironmentBuildOptions: config,
|
||
|
}
|
||
|
|
||
|
if err := build.Start(values); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
if err := build.Poll(); err != nil {
|
||
|
return "", errors.Wrap(err, "Error during the polling for the final state of the build run")
|
||
|
}
|
||
|
|
||
|
if err := build.PrintLogs(); err != nil {
|
||
|
return "", errors.Wrap(err, "Error printing the logs")
|
||
|
}
|
||
|
if err := build.EvaluteIfBuildSuccessful(); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
if err := build.Download(); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
if err := build.Publish(utils); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
finalValues, err := build.GetFinalValues()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return finalValues, nil
|
||
|
}
|
||
|
|
||
|
type myBuild struct {
|
||
|
abapbuild.Build
|
||
|
*abapEnvironmentBuildOptions
|
||
|
}
|
||
|
|
||
|
func (b *myBuild) Start(values abapbuild.Values) error {
|
||
|
if err := b.Build.Start(b.abapEnvironmentBuildOptions.Phase, values); err != nil {
|
||
|
return errors.Wrap(err, "Error starting the build framework")
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (b *myBuild) EvaluteIfBuildSuccessful() error {
|
||
|
if err := b.Build.EvaluteIfBuildSuccessful(b.TreatWarningsAsError); err != nil {
|
||
|
return errors.Wrap(err, "Build ended without success")
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (b *myBuild) Download() error {
|
||
|
if b.DownloadAllResultFiles {
|
||
|
if err := b.DownloadAllResults(b.SubDirectoryForDownload, b.FilenamePrefixForDownload); err != nil {
|
||
|
return errors.Wrap(err, "Error during the download of the result files")
|
||
|
}
|
||
|
} else {
|
||
|
if err := b.DownloadResults(b.DownloadResultFilenames, b.SubDirectoryForDownload, b.FilenamePrefixForDownload); err != nil {
|
||
|
return errors.Wrapf(err, "Error during the download of the result files %s", b.DownloadResultFilenames)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (b *myBuild) Publish(utils *abapEnvironmentBuildUtils) error {
|
||
|
if b.PublishAllDownloadedResultFiles {
|
||
|
b.PublishAllDownloadedResults("abapEnvironmentBuild", *utils)
|
||
|
} else {
|
||
|
if err := b.PublishDownloadedResults("abapEnvironmentBuild", b.PublishResultFilenames, *utils); err != nil {
|
||
|
return errors.Wrapf(err, "Error during the publish of the result files %s", b.PublishResultFilenames)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (b *myBuild) GetFinalValues() (string, error) {
|
||
|
type cpeValue struct {
|
||
|
ValueID string `json:"value_id"`
|
||
|
Value string `json:"value"`
|
||
|
}
|
||
|
|
||
|
if err := b.GetValues(); err != nil {
|
||
|
return "", errors.Wrapf(err, "Error getting the values from build framework")
|
||
|
}
|
||
|
var cpeValues []cpeValue
|
||
|
byt, err := json.Marshal(&b.Build.Values)
|
||
|
if err != nil {
|
||
|
return "", errors.Wrapf(err, "Error converting the values from the build framework")
|
||
|
}
|
||
|
if err := json.Unmarshal(byt, &cpeValues); err != nil {
|
||
|
return "", errors.Wrapf(err, "Error converting the values from the build framework into the structure for the commonPipelineEnvironment")
|
||
|
}
|
||
|
jsonBytes, err := json.Marshal(cpeValues)
|
||
|
if err != nil {
|
||
|
return "", errors.Wrapf(err, "Error converting the converted values")
|
||
|
}
|
||
|
return string(jsonBytes), nil
|
||
|
}
|
||
|
|
||
|
// **********************************Generate Values**************************************************************
|
||
|
func generateValues(config *abapEnvironmentBuildOptions) (abapbuild.Values, error) {
|
||
|
var values abapbuild.Values
|
||
|
vE := valuesEvaluator{}
|
||
|
if err := vE.initialize(config.Values); err != nil {
|
||
|
return values, err
|
||
|
}
|
||
|
if err := vE.appendValues(config.CpeValues); err != nil {
|
||
|
return values, err
|
||
|
}
|
||
|
values.Values = vE.values
|
||
|
return values, nil
|
||
|
}
|
||
|
|
||
|
type valuesEvaluator struct {
|
||
|
values []abapbuild.Value
|
||
|
m map[string]string
|
||
|
}
|
||
|
|
||
|
func (vE *valuesEvaluator) initialize(stringValues string) error {
|
||
|
if err := json.Unmarshal([]byte(stringValues), &vE.values); err != nil {
|
||
|
log.SetErrorCategory(log.ErrorConfiguration)
|
||
|
return errors.Wrapf(err, "Could not convert the values %s from the config", stringValues)
|
||
|
}
|
||
|
|
||
|
vE.m = make(map[string]string)
|
||
|
for _, value := range vE.values {
|
||
|
if (len(value.ValueID) == 0) || (len(value.Value) == 0) {
|
||
|
log.SetErrorCategory(log.ErrorConfiguration)
|
||
|
return errors.Errorf("Values %s from config have not the right format", stringValues)
|
||
|
}
|
||
|
_, present := vE.m[value.ValueID]
|
||
|
if present {
|
||
|
log.SetErrorCategory(log.ErrorConfiguration)
|
||
|
return errors.Errorf("Value_id %s is not unique in the config", value.ValueID)
|
||
|
}
|
||
|
vE.m[value.ValueID] = value.Value
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (vE *valuesEvaluator) appendValues(stringValues string) error {
|
||
|
var values []abapbuild.Value
|
||
|
if len(stringValues) > 0 {
|
||
|
if err := json.Unmarshal([]byte(stringValues), &values); err != nil {
|
||
|
log.SetErrorCategory(log.ErrorConfiguration)
|
||
|
return errors.Wrapf(err, "Could not convert the values %s from the commonPipelineEnvironment", stringValues)
|
||
|
}
|
||
|
for i := len(values) - 1; i >= 0; i-- {
|
||
|
_, present := vE.m[values[i].ValueID]
|
||
|
if present || (values[i].ValueID == "PHASE") {
|
||
|
log.Entry().Infof("Value %s already exists in config -> discard this value", values[i])
|
||
|
values = append(values[:i], values[i+1:]...)
|
||
|
}
|
||
|
}
|
||
|
vE.values = append(vE.values, values...)
|
||
|
}
|
||
|
return nil
|
||
|
}
|