1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/cmd/abapEnvironmentBuild.go

271 lines
8.8 KiB
Go
Raw Normal View History

Generic build step (#3323) * new step abapEnvironmentBuild * Update piper.go * Update abapEnvironmentBuild.go * update yaml file * Logging for debugging * Update abaputils.go * Update connector.go * assigning connector * delete debugging logging * Update abapEnvironmentBuild.go * certificate to yaml * Update abapEnvironmentBuild.go * add scope * Update abapEnvironmentBuild.go * Update abapEnvironmentBuild.yaml * change certificate name in yaml * test my new gitscript * logging for debugging * debugging... * adding options to client. * skip verification * debugging * debugging... * switch of transportskipverification * changing connector return * deleting additional set options * fixed timeout error * adding certificate * testing without certificate set * testing with certificate set * download, publish and value logic * write values to cpe * logging * adding condition on string length * change publishmethod and some logging * change download method -> using references * evaluation of parameter for download * add case for empty string * adding unittests * Update mockClient.go * make abapEnvironmentBuildUtilsBundle powerful * refactor abapEnvironmentBuild into pieces * check error message * check error message 2 * check error message 3 * check error message 4 * remove check error message * cleanup * adding unittests * unittests and docu * docu * docu * Update abapEnvironmentBuild.md * removing trailing spaces and adding empty lines in docu * Update abapEnvironmentBuild.md * fixing unittest and PR recommen * Update abapEnvironmentPipelineStageBuild.groovy * Update abapEnvironmentPipelineStageBuild.groovy * Update abapEnvironmentPipelineStageBuild.groovy * Update abapEnvironmentPipelineStageBuild.groovy * changes derived from pull request Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>
2021-12-06 15:43:37 +02:00
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
}