mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-04 04:07:16 +02:00
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>
This commit is contained in:
parent
24d8584c3f
commit
e90856d5bf
270
cmd/abapEnvironmentBuild.go
Normal file
270
cmd/abapEnvironmentBuild.go
Normal file
@ -0,0 +1,270 @@
|
||||
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
|
||||
}
|
424
cmd/abapEnvironmentBuild_generated.go
Normal file
424
cmd/abapEnvironmentBuild_generated.go
Normal file
@ -0,0 +1,424 @@
|
||||
// Code generated by piper's step-generator. DO NOT EDIT.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperenv"
|
||||
"github.com/SAP/jenkins-library/pkg/splunk"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/SAP/jenkins-library/pkg/validation"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type abapEnvironmentBuildOptions struct {
|
||||
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
|
||||
CfOrg string `json:"cfOrg,omitempty"`
|
||||
CfSpace string `json:"cfSpace,omitempty"`
|
||||
CfServiceInstance string `json:"cfServiceInstance,omitempty"`
|
||||
CfServiceKeyName string `json:"cfServiceKeyName,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Phase string `json:"phase,omitempty"`
|
||||
Values string `json:"values,omitempty"`
|
||||
DownloadAllResultFiles bool `json:"downloadAllResultFiles,omitempty"`
|
||||
DownloadResultFilenames []string `json:"downloadResultFilenames,omitempty"`
|
||||
PublishAllDownloadedResultFiles bool `json:"publishAllDownloadedResultFiles,omitempty"`
|
||||
PublishResultFilenames []string `json:"publishResultFilenames,omitempty"`
|
||||
SubDirectoryForDownload string `json:"subDirectoryForDownload,omitempty"`
|
||||
FilenamePrefixForDownload string `json:"filenamePrefixForDownload,omitempty"`
|
||||
TreatWarningsAsError bool `json:"treatWarningsAsError,omitempty"`
|
||||
MaxRuntimeInMinutes int `json:"maxRuntimeInMinutes,omitempty"`
|
||||
PollingIntervallInSeconds int `json:"pollingIntervallInSeconds,omitempty"`
|
||||
CertificateNames []string `json:"certificateNames,omitempty"`
|
||||
CpeValues string `json:"cpeValues,omitempty"`
|
||||
}
|
||||
|
||||
type abapEnvironmentBuildCommonPipelineEnvironment struct {
|
||||
abap struct {
|
||||
buildValues string
|
||||
}
|
||||
}
|
||||
|
||||
func (p *abapEnvironmentBuildCommonPipelineEnvironment) persist(path, resourceName string) {
|
||||
content := []struct {
|
||||
category string
|
||||
name string
|
||||
value interface{}
|
||||
}{
|
||||
{category: "abap", name: "buildValues", value: p.abap.buildValues},
|
||||
}
|
||||
|
||||
errCount := 0
|
||||
for _, param := range content {
|
||||
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Error("Error persisting piper environment.")
|
||||
errCount++
|
||||
}
|
||||
}
|
||||
if errCount > 0 {
|
||||
log.Entry().Fatal("failed to persist Piper environment")
|
||||
}
|
||||
}
|
||||
|
||||
// AbapEnvironmentBuildCommand Executes builds as defined with the build framework
|
||||
func AbapEnvironmentBuildCommand() *cobra.Command {
|
||||
const STEP_NAME = "abapEnvironmentBuild"
|
||||
|
||||
metadata := abapEnvironmentBuildMetadata()
|
||||
var stepConfig abapEnvironmentBuildOptions
|
||||
var startTime time.Time
|
||||
var commonPipelineEnvironment abapEnvironmentBuildCommonPipelineEnvironment
|
||||
var logCollector *log.CollectorHook
|
||||
var splunkClient *splunk.Splunk
|
||||
telemetryClient := &telemetry.Telemetry{}
|
||||
|
||||
var createAbapEnvironmentBuildCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "Executes builds as defined with the build framework",
|
||||
Long: `Executes builds as defined with the build framework. Transaction overview /n/BUILD/OVERVIEW`,
|
||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||
startTime = time.Now()
|
||||
log.SetStepName(STEP_NAME)
|
||||
log.SetVerbose(GeneralConfig.Verbose)
|
||||
|
||||
GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens)
|
||||
|
||||
path, _ := os.Getwd()
|
||||
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
|
||||
log.RegisterHook(fatalHook)
|
||||
|
||||
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
log.RegisterSecret(stepConfig.Username)
|
||||
log.RegisterSecret(stepConfig.Password)
|
||||
|
||||
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
|
||||
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
|
||||
log.RegisterHook(&sentryHook)
|
||||
}
|
||||
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunkClient = &splunk.Splunk{}
|
||||
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
|
||||
log.RegisterHook(logCollector)
|
||||
}
|
||||
|
||||
validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = validation.ValidateStruct(stepConfig); err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
stepTelemetryData := telemetry.CustomData{}
|
||||
stepTelemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
config.RemoveVaultSecretFiles()
|
||||
commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
|
||||
stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
stepTelemetryData.ErrorCategory = log.GetErrorCategory().String()
|
||||
stepTelemetryData.PiperCommitHash = GitCommit
|
||||
telemetryClient.SetData(&stepTelemetryData)
|
||||
telemetryClient.Send()
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunkClient.Send(telemetryClient.GetData(), logCollector)
|
||||
}
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunkClient.Initialize(GeneralConfig.CorrelationID,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Dsn,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Token,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Index,
|
||||
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
|
||||
}
|
||||
abapEnvironmentBuild(stepConfig, &stepTelemetryData, &commonPipelineEnvironment)
|
||||
stepTelemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addAbapEnvironmentBuildFlags(createAbapEnvironmentBuildCmd, &stepConfig)
|
||||
return createAbapEnvironmentBuildCmd
|
||||
}
|
||||
|
||||
func addAbapEnvironmentBuildFlags(cmd *cobra.Command, stepConfig *abapEnvironmentBuildOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API endpoint")
|
||||
cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "Cloud Foundry target organization")
|
||||
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space")
|
||||
cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance")
|
||||
cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key")
|
||||
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP Cloud Platform ABAP Environment system")
|
||||
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User")
|
||||
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password")
|
||||
cmd.Flags().StringVar(&stepConfig.Phase, "phase", os.Getenv("PIPER_phase"), "Phase as specified in the build script in the backend system")
|
||||
cmd.Flags().StringVar(&stepConfig.Values, "values", os.Getenv("PIPER_values"), "Input values for the build framework")
|
||||
cmd.Flags().BoolVar(&stepConfig.DownloadAllResultFiles, "downloadAllResultFiles", false, "If true, all build artefacts are downloaded")
|
||||
cmd.Flags().StringSliceVar(&stepConfig.DownloadResultFilenames, "downloadResultFilenames", []string{}, "Only the specified files are downloaded, downloadAllResultFiles is true, this parameter is ignored")
|
||||
cmd.Flags().BoolVar(&stepConfig.PublishAllDownloadedResultFiles, "publishAllDownloadedResultFiles", false, "If true, it publishes all downloaded files")
|
||||
cmd.Flags().StringSliceVar(&stepConfig.PublishResultFilenames, "publishResultFilenames", []string{}, "Only the specified files get published, in case the file was not downloaded before an error occures")
|
||||
cmd.Flags().StringVar(&stepConfig.SubDirectoryForDownload, "subDirectoryForDownload", os.Getenv("PIPER_subDirectoryForDownload"), "Target directory to store the downloaded files, {buildID} and {taskID} can be used and will be resolved accordingly")
|
||||
cmd.Flags().StringVar(&stepConfig.FilenamePrefixForDownload, "filenamePrefixForDownload", os.Getenv("PIPER_filenamePrefixForDownload"), "Filename prefix for the downloaded files, {buildID} and {taskID} can be used and will be resolved accordingly")
|
||||
cmd.Flags().BoolVar(&stepConfig.TreatWarningsAsError, "treatWarningsAsError", false, "If a warrning occures, the step will be set to unstable")
|
||||
cmd.Flags().IntVar(&stepConfig.MaxRuntimeInMinutes, "maxRuntimeInMinutes", 360, "maximal runtime of the step in minutes")
|
||||
cmd.Flags().IntVar(&stepConfig.PollingIntervallInSeconds, "pollingIntervallInSeconds", 60, "wait time in seconds till next status request in the backend system")
|
||||
cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "certificates for the backend system, this certificates needs to be stored in .pipeline/trustStore")
|
||||
cmd.Flags().StringVar(&stepConfig.CpeValues, "cpeValues", os.Getenv("PIPER_cpeValues"), "Values taken from the previous step, if a value was also specified in the config file, the value from cpe will be discarded")
|
||||
|
||||
cmd.MarkFlagRequired("username")
|
||||
cmd.MarkFlagRequired("password")
|
||||
cmd.MarkFlagRequired("phase")
|
||||
cmd.MarkFlagRequired("downloadAllResultFiles")
|
||||
cmd.MarkFlagRequired("publishAllDownloadedResultFiles")
|
||||
cmd.MarkFlagRequired("treatWarningsAsError")
|
||||
cmd.MarkFlagRequired("maxRuntimeInMinutes")
|
||||
cmd.MarkFlagRequired("pollingIntervallInSeconds")
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func abapEnvironmentBuildMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "abapEnvironmentBuild",
|
||||
Aliases: []config.Alias{},
|
||||
Description: "Executes builds as defined with the build framework",
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Secrets: []config.StepSecrets{
|
||||
{Name: "abapCredentialsId", Description: "Jenkins credentials ID containing user and password to authenticate to the Cloud Platform ABAP Environment system or the Cloud Foundry API", Type: "jenkins", Aliases: []config.Alias{{Name: "cfCredentialsId", Deprecated: false}, {Name: "credentialsId", Deprecated: false}}},
|
||||
},
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "cfApiEndpoint",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/apiEndpoint"}},
|
||||
Default: os.Getenv("PIPER_cfApiEndpoint"),
|
||||
},
|
||||
{
|
||||
Name: "cfOrg",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/org"}},
|
||||
Default: os.Getenv("PIPER_cfOrg"),
|
||||
},
|
||||
{
|
||||
Name: "cfSpace",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/space"}},
|
||||
Default: os.Getenv("PIPER_cfSpace"),
|
||||
},
|
||||
{
|
||||
Name: "cfServiceInstance",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/serviceInstance"}},
|
||||
Default: os.Getenv("PIPER_cfServiceInstance"),
|
||||
},
|
||||
{
|
||||
Name: "cfServiceKeyName",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}},
|
||||
Default: os.Getenv("PIPER_cfServiceKeyName"),
|
||||
},
|
||||
{
|
||||
Name: "host",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_host"),
|
||||
},
|
||||
{
|
||||
Name: "username",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_username"),
|
||||
},
|
||||
{
|
||||
Name: "password",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_password"),
|
||||
},
|
||||
{
|
||||
Name: "phase",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_phase"),
|
||||
},
|
||||
{
|
||||
Name: "values",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_values"),
|
||||
},
|
||||
{
|
||||
Name: "downloadAllResultFiles",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "bool",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: false,
|
||||
},
|
||||
{
|
||||
Name: "downloadResultFilenames",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "[]string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: []string{},
|
||||
},
|
||||
{
|
||||
Name: "publishAllDownloadedResultFiles",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "bool",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: false,
|
||||
},
|
||||
{
|
||||
Name: "publishResultFilenames",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "[]string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: []string{},
|
||||
},
|
||||
{
|
||||
Name: "subDirectoryForDownload",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_subDirectoryForDownload"),
|
||||
},
|
||||
{
|
||||
Name: "filenamePrefixForDownload",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_filenamePrefixForDownload"),
|
||||
},
|
||||
{
|
||||
Name: "treatWarningsAsError",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "bool",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: false,
|
||||
},
|
||||
{
|
||||
Name: "maxRuntimeInMinutes",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "int",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: 360,
|
||||
},
|
||||
{
|
||||
Name: "pollingIntervallInSeconds",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "int",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: 60,
|
||||
},
|
||||
{
|
||||
Name: "certificateNames",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "[]string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: []string{},
|
||||
},
|
||||
{
|
||||
Name: "cpeValues",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "abap/buildValues",
|
||||
},
|
||||
},
|
||||
Scope: []string{},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_cpeValues"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []config.Container{
|
||||
{Name: "cf", Image: "ppiper/cf-cli:7"},
|
||||
},
|
||||
Outputs: config.StepOutputs{
|
||||
Resources: []config.StepResources{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Type: "piperEnvironment",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"Name": "abap/buildValues"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
17
cmd/abapEnvironmentBuild_generated_test.go
Normal file
17
cmd/abapEnvironmentBuild_generated_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAbapEnvironmentBuildCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCmd := AbapEnvironmentBuildCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procedure
|
||||
assert.Equal(t, "abapEnvironmentBuild", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
150
cmd/abapEnvironmentBuild_test.go
Normal file
150
cmd/abapEnvironmentBuild_test.go
Normal file
@ -0,0 +1,150 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
|
||||
"github.com/SAP/jenkins-library/pkg/abaputils"
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type abapEnvironmentBuildMockUtils struct {
|
||||
*mock.ExecMockRunner
|
||||
*abapbuild.MockClient
|
||||
}
|
||||
|
||||
func newAbapEnvironmentBuildTestsUtils() abapEnvironmentBuildUtils {
|
||||
mC := abapbuild.GetBuildMockClient()
|
||||
utils := abapEnvironmentBuildMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
MockClient: &mC,
|
||||
}
|
||||
return &utils
|
||||
}
|
||||
func (mB abapEnvironmentBuildMockUtils) PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
|
||||
}
|
||||
func (mB abapEnvironmentBuildMockUtils) GetAbapCommunicationArrangementInfo(options abaputils.AbapEnvironmentOptions, oDataURL string) (abaputils.ConnectionDetailsHTTP, error) {
|
||||
var cd abaputils.ConnectionDetailsHTTP
|
||||
cd.URL = "/sap/opu/odata/BUILD/CORE_SRV"
|
||||
return cd, nil
|
||||
}
|
||||
func (mB abapEnvironmentBuildMockUtils) GetPollIntervall() time.Duration {
|
||||
return 1 * time.Microsecond
|
||||
}
|
||||
|
||||
func (mB abapEnvironmentBuildMockUtils) getMaxRuntime() time.Duration {
|
||||
return 1 * time.Second
|
||||
}
|
||||
func (mB abapEnvironmentBuildMockUtils) getPollingIntervall() time.Duration {
|
||||
return 1 * time.Microsecond
|
||||
}
|
||||
|
||||
func TestRunAbapEnvironmentBuild(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
cpe := abapEnvironmentBuildCommonPipelineEnvironment{}
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
config.DownloadAllResultFiles = true
|
||||
config.PublishAllDownloadedResultFiles = true
|
||||
utils := newAbapEnvironmentBuildTestsUtils()
|
||||
// test
|
||||
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
|
||||
// assert
|
||||
finalValues := `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"AunitValue1"},{"value_id":"MyId2","value":"AunitValue2"},{"value_id":"BUILD_FRAMEWORK_MODE","value":"P"}]`
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, finalValues, cpe.abap.buildValues)
|
||||
})
|
||||
|
||||
t.Run("happy path, download only one", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
cpe := abapEnvironmentBuildCommonPipelineEnvironment{}
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
config.DownloadResultFilenames = []string{"SAR_XML"}
|
||||
config.PublishResultFilenames = []string{"SAR_XML"}
|
||||
utils := newAbapEnvironmentBuildTestsUtils()
|
||||
// test
|
||||
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("error path, try to publish file, which was not downloaded", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
cpe := abapEnvironmentBuildCommonPipelineEnvironment{}
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
config.DownloadResultFilenames = []string{"DELIVERY_LOGS.ZIP"}
|
||||
config.PublishResultFilenames = []string{"SAR_XML"}
|
||||
utils := newAbapEnvironmentBuildTestsUtils()
|
||||
// test
|
||||
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
|
||||
// assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("error path, try to download file which does not exist", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
cpe := abapEnvironmentBuildCommonPipelineEnvironment{}
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
config.DownloadResultFilenames = []string{"DOES_NOT_EXIST"}
|
||||
config.PublishAllDownloadedResultFiles = true
|
||||
utils := newAbapEnvironmentBuildTestsUtils()
|
||||
// test
|
||||
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
|
||||
// assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateValues(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
config.CpeValues = `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"PACKAGES","value":"CPE_PACKAGE"},{"value_id":"MyId2","value":"Value2"}]`
|
||||
// test
|
||||
values, err := generateValues(&config)
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(values.Values))
|
||||
assert.Equal(t, "/BUILD/AUNIT_DUMMY_TESTS", values.Values[0].Value)
|
||||
assert.Equal(t, "Value1", values.Values[1].Value)
|
||||
assert.Equal(t, "Value2", values.Values[2].Value)
|
||||
})
|
||||
t.Run("error path - duplicate in config", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
// test
|
||||
values, err := generateValues(&config)
|
||||
// assert
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, 0, len(values.Values))
|
||||
})
|
||||
t.Run("error path - bad formating in config.Values", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// init
|
||||
config := abapEnvironmentBuildOptions{}
|
||||
config.Values = `[{"task_id":"PACKAGES","task":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]`
|
||||
// test
|
||||
_, err := generateValues(&config)
|
||||
// assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
@ -16,6 +16,7 @@ func GetAllStepMetadata() map[string]config.StepData {
|
||||
"abapAddonAssemblyKitReserveNextPackages": abapAddonAssemblyKitReserveNextPackagesMetadata(),
|
||||
"abapEnvironmentAssembleConfirm": abapEnvironmentAssembleConfirmMetadata(),
|
||||
"abapEnvironmentAssemblePackages": abapEnvironmentAssemblePackagesMetadata(),
|
||||
"abapEnvironmentBuild": abapEnvironmentBuildMetadata(),
|
||||
"abapEnvironmentCheckoutBranch": abapEnvironmentCheckoutBranchMetadata(),
|
||||
"abapEnvironmentCloneGitRepo": abapEnvironmentCloneGitRepoMetadata(),
|
||||
"abapEnvironmentCreateSystem": abapEnvironmentCreateSystemMetadata(),
|
||||
|
@ -128,6 +128,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(JsonApplyPatchCommand())
|
||||
rootCmd.AddCommand(KanikoExecuteCommand())
|
||||
rootCmd.AddCommand(CnbBuildCommand())
|
||||
rootCmd.AddCommand(AbapEnvironmentBuildCommand())
|
||||
rootCmd.AddCommand(AbapEnvironmentAssemblePackagesCommand())
|
||||
rootCmd.AddCommand(AbapAddonAssemblyKitCheckCVsCommand())
|
||||
rootCmd.AddCommand(AbapAddonAssemblyKitCheckPVCommand())
|
||||
|
86
documentation/docs/steps/abapEnvironmentBuild.md
Normal file
86
documentation/docs/steps/abapEnvironmentBuild.md
Normal file
@ -0,0 +1,86 @@
|
||||
# ${docGenStepName}
|
||||
|
||||
## ${docGenDescription}
|
||||
|
||||
## Prerequisites SAP BTP, ABAP environment
|
||||
|
||||
* A SAP BTP, ABAP environment system is available.
|
||||
* This can be created manually on Cloud Foundry.
|
||||
* In a pipeline, you can do this, for example, with the step [cloudFoundryCreateService](https://sap.github.io/jenkins-library/steps/cloudFoundryCreateService/).
|
||||
* Communication Scenario [“SAP BTP, ABAP Environment - Software Assembly Integration (SAP_COM_0582)“](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/26b8df5435c649aa8ea7b3688ad5bb0a.html) is setup for this system.
|
||||
* E.g. a [Communication User](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/0377adea0401467f939827242c1f4014.html), a [Communication System](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/1bfe32ae08074b7186e375ab425fb114.html) and a [Communication Arrangement](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/a0771f6765f54e1c8193ad8582a32edb.html) are configured.
|
||||
* This can be done manually through the respective applications on the SAP BTP, ABAP environment system,
|
||||
* or through creating a service key for the system on cloud foundry with the parameters {“scenario_id”: “SAP_COM_0582", “type”: “basic”}.
|
||||
* In a pipeline, you can do this, for example, with the step [cloudFoundryCreateServiceKey](https://sap.github.io/jenkins-library/steps/cloudFoundryCreateServiceKey/).
|
||||
* You have following options to provide the ABAP endpoint configuration:
|
||||
* The host and credentials the SAP BTP, ABAP environment system itself. The credentials must be configured for the Communication Scenario SAP_COM_0582.
|
||||
* The Cloud Foundry parameters (API endpoint, organization, space), credentials, the service instance for the ABAP service and the service key for the Communication Scenario SAP_COM_0582.
|
||||
* Only provide one of those options with the respective credentials. If all values are provided, the direct communication (via host) has priority.
|
||||
|
||||
## Prerequisites On Premise
|
||||
|
||||
* You need to specify the host and credentials to your system
|
||||
* A certificate for the system needs to be stored in .pipeline/trustStore and the name of the certificate needs to be handed over via the configuration
|
||||
|
||||
## ${docGenParameters}
|
||||
|
||||
## ${docGenConfiguration}
|
||||
|
||||
## ${docJenkinsPluginDependencies}
|
||||
|
||||
## Examples
|
||||
|
||||
### Configuration in the config.yml
|
||||
|
||||
If you want to use this step several time in one pipeline with different phases, the steps have to be put in different stages as it is not allowed to run the same step repeatedly in one stage.
|
||||
|
||||
The recommended way to configure your pipeline is via the config.yml file. In this case, calling the step in the Jenkinsfile is reduced to one line:
|
||||
|
||||
```groovy
|
||||
stage('MyPhase') {
|
||||
steps {
|
||||
abapEnvironmentBuild script: this
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to provide the host and credentials of the Communication Arrangement directly or you want to run in on premise, the configuration could look as follows:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
MyPhase:
|
||||
abapCredentialsId: 'abapCredentialsId',
|
||||
host: 'https://myABAPendpoint.com',
|
||||
```
|
||||
|
||||
Or by authenticating against Cloud Foundry and reading the Service Key details from there:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
MyPhase:
|
||||
abapCredentialsId: 'cfCredentialsId',
|
||||
cfApiEndpoint : 'https://test.server.com',
|
||||
cfOrg : 'cfOrg',
|
||||
cfSpace: 'cfSpace',
|
||||
cfServiceInstance: 'myServiceInstance',
|
||||
cfServiceKeyName: 'myServiceKey',
|
||||
```
|
||||
|
||||
One possible complete config example. Please note that the values are handed over as a string, which has inside a json structure:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
MyPhase:
|
||||
abapCredentialsId: 'abapCredentialsId'
|
||||
host: 'https://myABAPendpoint.com'
|
||||
certificateNames: ['myCert.cer']
|
||||
phase: 'MyPhase'
|
||||
values: '[{"value_id":"ID1","value":"Value1"},{"value_id":"ID2","value":"Value2"}]'
|
||||
downloadResultFilenames: ['File1','File2']
|
||||
publishResultFilenames: ['File2']
|
||||
subDirectoryForDownload: 'MyDir'
|
||||
filenamePrefixForDownload: 'MyPrefix'
|
||||
treatWarningsAsError: true
|
||||
maxRuntimeInMinutes: 360
|
||||
pollingIntervallInSeconds: 15
|
||||
```
|
@ -57,6 +57,7 @@ nav:
|
||||
- abapAddonAssemblyKitRegisterPackages: steps/abapAddonAssemblyKitRegisterPackages.md
|
||||
- abapAddonAssemblyKitReleasePackages: steps/abapAddonAssemblyKitReleasePackages.md
|
||||
- abapAddonAssemblyKitReserveNextPackages: steps/abapAddonAssemblyKitReserveNextPackages.md
|
||||
- abapEnvironmentBuild: steps/abapEnvironmentBuild.md
|
||||
- abapEnvironmentAssemblePackages: steps/abapEnvironmentAssemblePackages.md
|
||||
- abapEnvironmentAssembleConfirm: steps/abapEnvironmentAssembleConfirm.md
|
||||
- abapEnvironmentCheckoutBranch: steps/abapEnvironmentCheckoutBranch.md
|
||||
|
@ -2,11 +2,17 @@ package build
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RunState : Current Status of the Build
|
||||
@ -28,11 +34,12 @@ const (
|
||||
// Finished : Build Framework ended successful
|
||||
Finished RunState = "FINISHED"
|
||||
// Failed : Build Framework endded with error
|
||||
Failed RunState = "FAILED"
|
||||
loginfo msgty = "I"
|
||||
logwarning msgty = "W"
|
||||
logerror msgty = "E"
|
||||
logaborted msgty = "A"
|
||||
Failed RunState = "FAILED"
|
||||
loginfo msgty = "I"
|
||||
logwarning msgty = "W"
|
||||
logerror msgty = "E"
|
||||
logaborted msgty = "A"
|
||||
dummyResultName string = "Dummy"
|
||||
)
|
||||
|
||||
//******** structs needed for json convertion ********
|
||||
@ -113,6 +120,8 @@ type Result struct {
|
||||
Name string `json:"name"`
|
||||
AdditionalInfo string `json:"additional_info"`
|
||||
Mimetype string `json:"mimetype"`
|
||||
SavedFilename string
|
||||
DownloadPath string
|
||||
}
|
||||
|
||||
// Value : Returns Build Runtime Value
|
||||
@ -165,6 +174,39 @@ func (b *Build) Start(phase string, inputValues Values) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Poll : waits for the build framework to be finished
|
||||
func (b *Build) Poll() error {
|
||||
timeout := time.After(b.Connector.MaxRuntime)
|
||||
ticker := time.Tick(b.Connector.PollingInterval)
|
||||
for {
|
||||
select {
|
||||
case <-timeout:
|
||||
return errors.Errorf("Timed out: (max Runtime %v reached)", b.Connector.MaxRuntime)
|
||||
case <-ticker:
|
||||
b.Get()
|
||||
if !b.IsFinished() {
|
||||
log.Entry().Infof("Build is not yet finished, check again in %s", b.Connector.PollingInterval)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EvaluteIfBuildSuccessful : Checks the finale state of the build framework
|
||||
func (b *Build) EvaluteIfBuildSuccessful(treatWarningsAsError bool) error {
|
||||
if b.RunState == Failed {
|
||||
return errors.Errorf("Build ended with runState failed")
|
||||
}
|
||||
if treatWarningsAsError && b.ResultState == warning {
|
||||
return errors.Errorf("Build ended with resultState warning, setting to failed as configured")
|
||||
}
|
||||
if (b.ResultState == aborted) || (b.ResultState == erroneous) {
|
||||
return errors.Errorf("Build ended with resultState %s", b.ResultState)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get : Get all Build tasks
|
||||
func (b *Build) Get() error {
|
||||
appendum := "/builds('" + b.BuildID + "')"
|
||||
@ -204,7 +246,8 @@ func (b *Build) getTasks() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Build) getValues() error {
|
||||
// GetValues : Gets all Build values
|
||||
func (b *Build) GetValues() error {
|
||||
if len(b.Values) == 0 {
|
||||
appendum := "/builds('" + b.BuildID + "')/values"
|
||||
body, err := b.Connector.Get(appendum)
|
||||
@ -246,7 +289,8 @@ func (b *Build) PrintLogs() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Build) getResults() error {
|
||||
// GetResults : Gets all Build results
|
||||
func (b *Build) GetResults() error {
|
||||
if err := b.getTasks(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -269,26 +313,26 @@ func (t *task) printLogs() error {
|
||||
}
|
||||
|
||||
// GetResult : Returns the last Build artefact created from build step
|
||||
func (b *Build) GetResult(name string) (Result, error) {
|
||||
var Results []Result
|
||||
func (b *Build) GetResult(name string) (*Result, error) {
|
||||
var Results []*Result
|
||||
var returnResult Result
|
||||
if err := b.getResults(); err != nil {
|
||||
return returnResult, err
|
||||
if err := b.GetResults(); err != nil {
|
||||
return &returnResult, err
|
||||
}
|
||||
for _, task := range b.Tasks {
|
||||
for _, result := range task.Results {
|
||||
if result.Name == name {
|
||||
Results = append(Results, result)
|
||||
for i_task := range b.Tasks {
|
||||
for i_result := range b.Tasks[i_task].Results {
|
||||
if b.Tasks[i_task].Results[i_result].Name == name {
|
||||
Results = append(Results, &b.Tasks[i_task].Results[i_result])
|
||||
}
|
||||
}
|
||||
}
|
||||
switch len(Results) {
|
||||
case 0:
|
||||
return returnResult, errors.New("No result named " + name + " was found")
|
||||
return &returnResult, errors.New("No result named " + name + " was found")
|
||||
case 1:
|
||||
return Results[0], nil
|
||||
default:
|
||||
return returnResult, errors.New("More than one result with the name " + name + " was found")
|
||||
return &returnResult, errors.New("More than one result with the name " + name + " was found")
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,12 +373,83 @@ func (t *task) getResults() error {
|
||||
}
|
||||
if len(t.Results) == 0 {
|
||||
//prevent 2nd GET request - no new results will occure...
|
||||
t.Results = append(t.Results, Result{Name: "Dummy"})
|
||||
t.Results = append(t.Results, Result{Name: dummyResultName})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadAllResults : Downloads all build artefacts, saves it to basePath and the filenames can be modified with the filenamePrefix
|
||||
func (b *Build) DownloadAllResults(basePath string, filenamePrefix string) error {
|
||||
if err := b.GetResults(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i_task := range b.Tasks {
|
||||
//in case there was no result, there is only one entry with dummyResultName, obviously we don't want to download this
|
||||
if b.Tasks[i_task].Results[0].Name != dummyResultName {
|
||||
for i_result := range b.Tasks[i_task].Results {
|
||||
if err := b.Tasks[i_task].Results[i_result].DownloadWithFilenamePrefixAndTargetDirectory(basePath, filenamePrefix); err != nil {
|
||||
return errors.Wrapf(err, "Error during the download of file %s", b.Tasks[i_task].Results[i_result].Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadResults : Download results which are specified in filenames
|
||||
func (b *Build) DownloadResults(filenames []string, basePath string, filenamePrefix string) error {
|
||||
for _, name := range filenames {
|
||||
result, err := b.GetResult(name)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errors.Wrapf(err, "Problems finding the file %s, please check your config whether this file is really a result file", name)
|
||||
}
|
||||
if err := result.DownloadWithFilenamePrefixAndTargetDirectory(basePath, filenamePrefix); err != nil {
|
||||
return errors.Wrapf(err, "Error during the download of file %s", name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PublishAllDownloadedResults : publishes all build artefacts which were downloaded before
|
||||
func (b *Build) PublishAllDownloadedResults(stepname string, publish Publish) {
|
||||
var filesToPublish []piperutils.Path
|
||||
for i_task := range b.Tasks {
|
||||
for i_result := range b.Tasks[i_task].Results {
|
||||
if b.Tasks[i_task].Results[i_result].wasDownloaded() {
|
||||
filesToPublish = append(filesToPublish, piperutils.Path{Target: b.Tasks[i_task].Results[i_result].DownloadPath,
|
||||
Name: b.Tasks[i_task].Results[i_result].SavedFilename, Mandatory: true})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(filesToPublish) > 0 {
|
||||
publish.PersistReportsAndLinks(stepname, "", filesToPublish, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// PublishDownloadedResults : Publishes build artefacts specified in filenames
|
||||
func (b *Build) PublishDownloadedResults(stepname string, filenames []string, publish Publish) error {
|
||||
var filesToPublish []piperutils.Path
|
||||
for i := range filenames {
|
||||
result, err := b.GetResult(filenames[i])
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errors.Wrapf(err, "Problems finding the file %s, please check your config whether this file is really a result file", filenames[i])
|
||||
}
|
||||
if result.wasDownloaded() {
|
||||
filesToPublish = append(filesToPublish, piperutils.Path{Target: result.DownloadPath, Name: result.SavedFilename, Mandatory: true})
|
||||
} else {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errors.Errorf("Trying to publish the file %s which was not downloaded", result.Name)
|
||||
}
|
||||
}
|
||||
if len(filesToPublish) > 0 {
|
||||
publish.PersistReportsAndLinks(stepname, "", filesToPublish, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Download : Provides the atrefact of build step
|
||||
func (result *Result) Download(downloadPath string) error {
|
||||
appendum := fmt.Sprint("/results(build_id='", result.BuildID, "',task_id=", result.TaskID, ",name='", result.Name, "')/$value")
|
||||
@ -342,6 +457,57 @@ func (result *Result) Download(downloadPath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// DownloadWithFilenamePrefixAndTargetDirectory : downloads build artefact, saves it to basePath and the filename can be modified with the filenamePrefix
|
||||
func (result *Result) DownloadWithFilenamePrefixAndTargetDirectory(basePath string, filenamePrefix string) error {
|
||||
basePath, err := result.resolveParamter(basePath)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not resolve parameter %s for the target directory", basePath)
|
||||
}
|
||||
filenamePrefix, err = result.resolveParamter(filenamePrefix)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not resolve parameter %s for the filename prefix", filenamePrefix)
|
||||
}
|
||||
appendum := fmt.Sprint("/results(build_id='", result.BuildID, "',task_id=", result.TaskID, ",name='", result.Name, "')/$value")
|
||||
filename := filenamePrefix + result.Name
|
||||
downloadPath := filepath.Join(path.Base(basePath), path.Base(filename))
|
||||
if err := result.connector.Download(appendum, downloadPath); err != nil {
|
||||
log.SetErrorCategory(log.ErrorInfrastructure)
|
||||
return errors.Wrapf(err, "Could not download %s", result.Name)
|
||||
}
|
||||
result.SavedFilename = filename
|
||||
result.DownloadPath = downloadPath
|
||||
log.Entry().Infof("Saved file %s as %s to %s", result.Name, result.SavedFilename, result.DownloadPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (result *Result) resolveParamter(parameter string) (string, error) {
|
||||
if len(parameter) == 0 {
|
||||
return parameter, nil
|
||||
}
|
||||
if (string(parameter[0]) == "{") && string(parameter[len(parameter)-1]) == "}" {
|
||||
trimmedParam := strings.ToLower(parameter[1 : len(parameter)-1])
|
||||
switch trimmedParam {
|
||||
case "buildid":
|
||||
return result.BuildID, nil
|
||||
case "taskid":
|
||||
return strconv.Itoa(result.TaskID), nil
|
||||
default:
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return "", errors.Errorf("Unknown parameter %s", parameter)
|
||||
}
|
||||
} else {
|
||||
return parameter, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (result *Result) wasDownloaded() bool {
|
||||
if len(result.DownloadPath) > 0 && len(result.SavedFilename) > 0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (logging *logStruct) print() {
|
||||
switch logging.Msgty {
|
||||
case loginfo:
|
||||
@ -376,3 +542,12 @@ func (vs Values) String() string {
|
||||
func (in inputForPost) String() string {
|
||||
return fmt.Sprintf(`{ "phase": "%s", "values": [%s]}`, in.phase, in.values.String())
|
||||
}
|
||||
|
||||
// *****************publish *******************************
|
||||
type Publish interface {
|
||||
PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path)
|
||||
}
|
||||
|
||||
func PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
|
||||
piperutils.PersistReportsAndLinks(stepName, workspace, reports, links)
|
||||
}
|
||||
|
@ -343,3 +343,44 @@ var responseGetValues = `{
|
||||
]
|
||||
}
|
||||
}`
|
||||
|
||||
func GetMockBuildTestDownloadPublish() Build {
|
||||
conn := new(Connector)
|
||||
conn.DownloadClient = &DownloadClientMock{}
|
||||
|
||||
results0 := []Result{
|
||||
{
|
||||
connector: *conn,
|
||||
Name: dummyResultName,
|
||||
},
|
||||
}
|
||||
results1 := []Result{
|
||||
{
|
||||
connector: *conn,
|
||||
Name: "File1",
|
||||
},
|
||||
{
|
||||
connector: *conn,
|
||||
Name: "File2",
|
||||
},
|
||||
{
|
||||
connector: *conn,
|
||||
Name: "File3",
|
||||
},
|
||||
}
|
||||
|
||||
build := Build{
|
||||
BuildID: "123",
|
||||
Tasks: []task{
|
||||
{
|
||||
TaskID: 0,
|
||||
Results: results0,
|
||||
},
|
||||
{
|
||||
TaskID: 1,
|
||||
Results: results1,
|
||||
},
|
||||
},
|
||||
}
|
||||
return build
|
||||
}
|
||||
|
@ -1,12 +1,24 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type mockPublish struct {
|
||||
reports []piperutils.Path
|
||||
}
|
||||
|
||||
func (mP *mockPublish) PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
|
||||
mP.reports = reports
|
||||
}
|
||||
|
||||
func testSetup(client piperhttp.Sender, buildID string) Build {
|
||||
conn := new(Connector)
|
||||
conn.Client = client
|
||||
@ -82,7 +94,7 @@ func TestGetValues(t *testing.T) {
|
||||
t.Run("Run getValues", func(t *testing.T) {
|
||||
b := testSetup(&ClMock{}, "ABIFNLDCSQPOVMXK4DNPBDRW2M")
|
||||
assert.Equal(t, 0, len(b.Values))
|
||||
err := b.getValues()
|
||||
err := b.GetValues()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 4, len(b.Values))
|
||||
assert.Equal(t, "PHASE", b.Values[0].ValueID)
|
||||
@ -99,7 +111,7 @@ func TestGetValues(t *testing.T) {
|
||||
func TestGetResults(t *testing.T) {
|
||||
t.Run("Run getResults", func(t *testing.T) {
|
||||
b := testSetup(&ClMock{}, "ABIFNLDCSQPOVMXK4DNPBDRW2M")
|
||||
err := b.getResults()
|
||||
err := b.GetResults()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(b.Tasks[0].Results))
|
||||
assert.Equal(t, 2, len(b.Tasks[1].Results))
|
||||
@ -113,3 +125,321 @@ func TestGetResults(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPoll(t *testing.T) {
|
||||
//arrange global
|
||||
build := new(Build)
|
||||
conn := new(Connector)
|
||||
conn.MaxRuntime = time.Duration(1 * time.Second)
|
||||
conn.PollingInterval = time.Duration(1 * time.Microsecond)
|
||||
conn.Baseurl = "/sap/opu/odata/BUILD/CORE_SRV"
|
||||
t.Run("Normal Poll", func(t *testing.T) {
|
||||
//arrange
|
||||
build.BuildID = "AKO22FYOFYPOXHOBVKXUTX3A3Q"
|
||||
mc := NewMockClient()
|
||||
mc.AddData(buildGet1)
|
||||
mc.AddData(buildGet2)
|
||||
conn.Client = &mc
|
||||
build.Connector = *conn
|
||||
//act
|
||||
err := build.Poll()
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Poll runstate failed", func(t *testing.T) {
|
||||
//arrange
|
||||
build.BuildID = "AKO22FYOFYPOXHOBVKXUTX3A3Q"
|
||||
mc := NewMockClient()
|
||||
mc.AddData(buildGet1)
|
||||
mc.AddData(buildGetRunStateFailed)
|
||||
conn.Client = &mc
|
||||
build.Connector = *conn
|
||||
//act
|
||||
err := build.Poll()
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Poll timeout", func(t *testing.T) {
|
||||
//arrange
|
||||
build.BuildID = "AKO22FYOFYPOXHOBVKXUTX3A3Q"
|
||||
conn.MaxRuntime = time.Duration(2 * time.Microsecond)
|
||||
conn.PollingInterval = time.Duration(1 * time.Microsecond)
|
||||
mc := NewMockClient()
|
||||
mc.AddData(buildGet1)
|
||||
mc.AddData(buildGet1)
|
||||
mc.AddData(buildGet2)
|
||||
conn.Client = &mc
|
||||
build.Connector = *conn
|
||||
//act
|
||||
err := build.Poll()
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvaluteIfBuildSuccessful(t *testing.T) {
|
||||
//arrange global
|
||||
build := new(Build)
|
||||
treatWarningsAsError := false
|
||||
t.Run("No error", func(t *testing.T) {
|
||||
//arrange
|
||||
build.RunState = Finished
|
||||
build.ResultState = successful
|
||||
//act
|
||||
err := build.EvaluteIfBuildSuccessful(treatWarningsAsError)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("RunState failed => Error", func(t *testing.T) {
|
||||
//arrange
|
||||
build.RunState = Failed
|
||||
//act
|
||||
err := build.EvaluteIfBuildSuccessful(treatWarningsAsError)
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("ResultState aborted => Error", func(t *testing.T) {
|
||||
//arrange
|
||||
build.RunState = Finished
|
||||
build.ResultState = aborted
|
||||
//act
|
||||
err := build.EvaluteIfBuildSuccessful(treatWarningsAsError)
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("ResultState erroneous => Error", func(t *testing.T) {
|
||||
//arrange
|
||||
build.RunState = Finished
|
||||
build.ResultState = erroneous
|
||||
//act
|
||||
err := build.EvaluteIfBuildSuccessful(treatWarningsAsError)
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("ResultState warning, treatWarningsAsError false => No error", func(t *testing.T) {
|
||||
//arrange
|
||||
build.RunState = Finished
|
||||
build.ResultState = warning
|
||||
//act
|
||||
err := build.EvaluteIfBuildSuccessful(treatWarningsAsError)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("ResultState warning, treatWarningsAsError true => error", func(t *testing.T) {
|
||||
//arrange
|
||||
build.RunState = Finished
|
||||
build.ResultState = warning
|
||||
treatWarningsAsError = true
|
||||
//act
|
||||
err := build.EvaluteIfBuildSuccessful(treatWarningsAsError)
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadWithFilenamePrefixAndTargetDirectory(t *testing.T) {
|
||||
//arrange global
|
||||
result := new(Result)
|
||||
result.BuildID = "123456789"
|
||||
result.TaskID = 1
|
||||
result.Name = "MyFile"
|
||||
conn := new(Connector)
|
||||
conn.DownloadClient = &DownloadClientMock{}
|
||||
result.connector = *conn
|
||||
t.Run("Download without extension", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := ""
|
||||
filenamePrefix := ""
|
||||
//act
|
||||
err := result.DownloadWithFilenamePrefixAndTargetDirectory(basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "MyFile", result.SavedFilename)
|
||||
assert.Equal(t, "MyFile", result.DownloadPath)
|
||||
})
|
||||
t.Run("Download with extensions", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := "MyDir"
|
||||
filenamePrefix := "SuperFile_"
|
||||
//act
|
||||
err := result.DownloadWithFilenamePrefixAndTargetDirectory(basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "SuperFile_MyFile", result.SavedFilename)
|
||||
downloadPath := filepath.Join(path.Base(basePath), path.Base("SuperFile_MyFile"))
|
||||
assert.Equal(t, downloadPath, result.DownloadPath)
|
||||
})
|
||||
t.Run("Download with parameter", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := "{BuildID}"
|
||||
filenamePrefix := "{taskid}"
|
||||
//act
|
||||
err := result.DownloadWithFilenamePrefixAndTargetDirectory(basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "1MyFile", result.SavedFilename)
|
||||
downloadPath := filepath.Join(path.Base("123456789"), path.Base("1MyFile"))
|
||||
assert.Equal(t, downloadPath, result.DownloadPath)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadAllResults(t *testing.T) {
|
||||
//arrange global
|
||||
build := GetMockBuildTestDownloadPublish()
|
||||
t.Run("Download without extension", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := ""
|
||||
filenamePrefix := ""
|
||||
//act
|
||||
err := build.DownloadAllResults(basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].SavedFilename)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "File1", build.Tasks[1].Results[0].SavedFilename)
|
||||
assert.Equal(t, "File1", build.Tasks[1].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "File2", build.Tasks[1].Results[1].SavedFilename)
|
||||
assert.Equal(t, "File2", build.Tasks[1].Results[1].DownloadPath)
|
||||
})
|
||||
t.Run("Download with extension", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := ""
|
||||
filenamePrefix := "SuperFile_"
|
||||
//act
|
||||
err := build.DownloadAllResults(basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].SavedFilename)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "SuperFile_File1", build.Tasks[1].Results[0].SavedFilename)
|
||||
assert.Equal(t, "SuperFile_File1", build.Tasks[1].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "SuperFile_File2", build.Tasks[1].Results[1].SavedFilename)
|
||||
assert.Equal(t, "SuperFile_File2", build.Tasks[1].Results[1].DownloadPath)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadResults(t *testing.T) {
|
||||
//arrange global
|
||||
build := GetMockBuildTestDownloadPublish()
|
||||
t.Run("Download existing", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := ""
|
||||
filenamePrefix := ""
|
||||
filenames := []string{"File1", "File3"}
|
||||
//act
|
||||
err := build.DownloadResults(filenames, basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].SavedFilename)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "File1", build.Tasks[1].Results[0].SavedFilename)
|
||||
assert.Equal(t, "File1", build.Tasks[1].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "", build.Tasks[1].Results[1].SavedFilename)
|
||||
assert.Equal(t, "", build.Tasks[1].Results[1].DownloadPath)
|
||||
|
||||
assert.Equal(t, "File3", build.Tasks[1].Results[2].SavedFilename)
|
||||
assert.Equal(t, "File3", build.Tasks[1].Results[2].DownloadPath)
|
||||
})
|
||||
t.Run("Try to download non existing", func(t *testing.T) {
|
||||
//arrange
|
||||
basePath := ""
|
||||
filenamePrefix := ""
|
||||
filenames := []string{"File1", "File4"}
|
||||
//act
|
||||
err := build.DownloadResults(filenames, basePath, filenamePrefix)
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].SavedFilename)
|
||||
assert.Equal(t, "", build.Tasks[0].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "File1", build.Tasks[1].Results[0].SavedFilename)
|
||||
assert.Equal(t, "File1", build.Tasks[1].Results[0].DownloadPath)
|
||||
|
||||
assert.Equal(t, "", build.Tasks[1].Results[1].SavedFilename)
|
||||
assert.Equal(t, "", build.Tasks[1].Results[1].DownloadPath)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPublishAllDownloadedResults(t *testing.T) {
|
||||
t.Run("Something was downloaded", func(t *testing.T) {
|
||||
//arrange
|
||||
build := GetMockBuildTestDownloadPublish()
|
||||
mP := mockPublish{}
|
||||
build.Tasks[1].Results[0].SavedFilename = "File1"
|
||||
build.Tasks[1].Results[0].DownloadPath = "Dir1/File1"
|
||||
build.Tasks[1].Results[2].SavedFilename = "File3"
|
||||
build.Tasks[1].Results[2].DownloadPath = "File3"
|
||||
//act
|
||||
build.PublishAllDownloadedResults("MyStep", &mP)
|
||||
//assert
|
||||
publishedFiles := []piperutils.Path{
|
||||
{
|
||||
Target: "Dir1/File1",
|
||||
Name: "File1",
|
||||
Mandatory: true,
|
||||
},
|
||||
{
|
||||
Target: "File3",
|
||||
Name: "File3",
|
||||
Mandatory: true,
|
||||
},
|
||||
}
|
||||
assert.Equal(t, publishedFiles, mP.reports)
|
||||
})
|
||||
t.Run("Nothing was downloaded", func(t *testing.T) {
|
||||
//arrange
|
||||
build := GetMockBuildTestDownloadPublish()
|
||||
mP := mockPublish{}
|
||||
//act
|
||||
build.PublishAllDownloadedResults("MyStep", &mP)
|
||||
//assert
|
||||
assert.Equal(t, 0, len(mP.reports))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPublishDownloadedResults(t *testing.T) {
|
||||
filenames := []string{"File1", "File3"}
|
||||
t.Run("Publish downloaded files", func(t *testing.T) {
|
||||
//arrange
|
||||
build := GetMockBuildTestDownloadPublish()
|
||||
mP := mockPublish{}
|
||||
build.Tasks[1].Results[0].SavedFilename = "SuperFile_File1"
|
||||
build.Tasks[1].Results[0].DownloadPath = "Dir1/SuperFile_File1"
|
||||
build.Tasks[1].Results[2].SavedFilename = "File3"
|
||||
build.Tasks[1].Results[2].DownloadPath = "File3"
|
||||
//act
|
||||
err := build.PublishDownloadedResults("MyStep", filenames, &mP)
|
||||
//assert
|
||||
assert.NoError(t, err)
|
||||
publishedFiles := []piperutils.Path{
|
||||
{
|
||||
Target: "Dir1/SuperFile_File1",
|
||||
Name: "SuperFile_File1",
|
||||
Mandatory: true,
|
||||
},
|
||||
{
|
||||
Target: "File3",
|
||||
Name: "File3",
|
||||
Mandatory: true,
|
||||
},
|
||||
}
|
||||
assert.Equal(t, publishedFiles, mP.reports)
|
||||
})
|
||||
t.Run("Try to publish file which was not downloaded", func(t *testing.T) {
|
||||
//arrange
|
||||
build := GetMockBuildTestDownloadPublish()
|
||||
mP := mockPublish{}
|
||||
build.Tasks[1].Results[0].SavedFilename = "SuperFile_File1"
|
||||
build.Tasks[1].Results[0].DownloadPath = "Dir1/SuperFile_File1"
|
||||
//act
|
||||
err := build.PublishDownloadedResults("MyStep", filenames, &mP)
|
||||
//assert
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ type ConnectorConfiguration struct {
|
||||
Password string
|
||||
AddonDescriptor string
|
||||
MaxRuntimeInMinutes int
|
||||
CertificateNames []string
|
||||
}
|
||||
|
||||
// HTTPSendLoader : combine both interfaces [sender, downloader]
|
||||
@ -170,9 +171,10 @@ func (conn *Connector) InitBuildFramework(config ConnectorConfiguration, com aba
|
||||
})
|
||||
cookieJar, _ := cookiejar.New(nil)
|
||||
conn.Client.SetOptions(piperhttp.ClientOptions{
|
||||
Username: connectionDetails.User,
|
||||
Password: connectionDetails.Password,
|
||||
CookieJar: cookieJar,
|
||||
Username: connectionDetails.User,
|
||||
Password: connectionDetails.Password,
|
||||
CookieJar: cookieJar,
|
||||
TrustedCerts: config.CertificateNames,
|
||||
})
|
||||
conn.Baseurl = connectionDetails.URL
|
||||
|
||||
|
@ -143,6 +143,7 @@ func GetBuildMockClient() MockClient {
|
||||
mc.AddData(buildGetTask11Result)
|
||||
mc.AddData(buildGetTask12Result)
|
||||
mc.AddData(buildGetTask11ResultMedia)
|
||||
mc.AddData(buildGetValues)
|
||||
|
||||
return mc
|
||||
}
|
||||
@ -254,6 +255,39 @@ var buildGet2 = MockData{
|
||||
StatusCode: 200,
|
||||
}
|
||||
|
||||
var buildGetRunStateFailed = MockData{
|
||||
Method: `GET`,
|
||||
Url: `/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')`,
|
||||
Body: `{
|
||||
"d" : {
|
||||
"__metadata" : {
|
||||
"id" : "https://7aa9d1a3-a876-464e-b59a-f26104452461.abap.stagingaws.hanavlab.ondemand.com/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')",
|
||||
"uri" : "https://7aa9d1a3-a876-464e-b59a-f26104452461.abap.stagingaws.hanavlab.ondemand.com/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')",
|
||||
"type" : "BUILD.CORE_SRV.xBUILDxVIEW_BUILDSType"
|
||||
},
|
||||
"build_id" : "AKO22FYOFYPOXHOBVKXUTX3A3Q",
|
||||
"run_state" : "FAILED",
|
||||
"result_state" : "SUCCESSFUL",
|
||||
"phase" : "BUILD_AOI",
|
||||
"entitytype" : "C",
|
||||
"startedby" : "CC0000000001",
|
||||
"started_at" : "\/Date(1614108520862+0000)\/",
|
||||
"finished_at" : "\/Date(1614108535350+0000)\/",
|
||||
"tasks" : {
|
||||
"__deferred" : {
|
||||
"uri" : "https://7aa9d1a3-a876-464e-b59a-f26104452461.abap.stagingaws.hanavlab.ondemand.com/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')/tasks"
|
||||
}
|
||||
},
|
||||
"values" : {
|
||||
"__deferred" : {
|
||||
"uri" : "https://7aa9d1a3-a876-464e-b59a-f26104452461.abap.stagingaws.hanavlab.ondemand.com/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')/values"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
StatusCode: 200,
|
||||
}
|
||||
|
||||
var buildGetTasks = MockData{
|
||||
Method: `GET`,
|
||||
Url: `/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')/tasks`,
|
||||
@ -1513,6 +1547,43 @@ var buildGetTask11ResultMedia = MockData{
|
||||
StatusCode: 200,
|
||||
}
|
||||
|
||||
var buildGetValues = MockData{
|
||||
Method: `GET`,
|
||||
Url: `/sap/opu/odata/BUILD/CORE_SRV/builds('AKO22FYOFYPOXHOBVKXUTX3A3Q')/values`,
|
||||
Body: `{
|
||||
"d": {
|
||||
"results": [
|
||||
{
|
||||
"build_id": "AKO22FYOFYPOXHOBVKXUTX3A3Q",
|
||||
"value_id": "PHASE",
|
||||
"value": "AUNIT"
|
||||
},
|
||||
{
|
||||
"build_id": "AKO22FYOFYPOXHOBVKXUTX3A3Q",
|
||||
"value_id": "PACKAGES",
|
||||
"value": "/BUILD/AUNIT_DUMMY_TESTS"
|
||||
},
|
||||
{
|
||||
"build_id": "AKO22FYOFYPOXHOBVKXUTX3A3Q",
|
||||
"value_id": "MyId1",
|
||||
"value": "AunitValue1"
|
||||
},
|
||||
{
|
||||
"build_id": "AKO22FYOFYPOXHOBVKXUTX3A3Q",
|
||||
"value_id": "MyId2",
|
||||
"value": "AunitValue2"
|
||||
},
|
||||
{
|
||||
"build_id": "AKO22FYOFYPOXHOBVKXUTX3A3Q",
|
||||
"value_id": "BUILD_FRAMEWORK_MODE",
|
||||
"value": "P"
|
||||
}
|
||||
]
|
||||
}
|
||||
}`,
|
||||
StatusCode: 200,
|
||||
}
|
||||
|
||||
var template = MockData{
|
||||
Method: `GET`,
|
||||
Url: ``,
|
||||
|
219
resources/metadata/abapEnvironmentBuild.yaml
Normal file
219
resources/metadata/abapEnvironmentBuild.yaml
Normal file
@ -0,0 +1,219 @@
|
||||
metadata:
|
||||
name: abapEnvironmentBuild
|
||||
description: "Executes builds as defined with the build framework"
|
||||
longDescription: |
|
||||
Executes builds as defined with the build framework. Transaction overview /n/BUILD/OVERVIEW
|
||||
spec:
|
||||
inputs:
|
||||
secrets:
|
||||
- name: abapCredentialsId
|
||||
description: Jenkins credentials ID containing user and password to authenticate to the Cloud Platform ABAP Environment system or the Cloud Foundry API
|
||||
type: jenkins
|
||||
aliases:
|
||||
- name: cfCredentialsId
|
||||
- name: credentialsId
|
||||
params:
|
||||
- name: cfApiEndpoint
|
||||
type: string
|
||||
description: Cloud Foundry API endpoint
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/apiEndpoint
|
||||
- name: cfOrg
|
||||
type: string
|
||||
description: Cloud Foundry target organization
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/org
|
||||
- name: cfSpace
|
||||
type: string
|
||||
description: Cloud Foundry target space
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/space
|
||||
- name: cfServiceInstance
|
||||
type: string
|
||||
description: Cloud Foundry Service Instance
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/serviceInstance
|
||||
- name: cfServiceKeyName
|
||||
type: string
|
||||
description: Cloud Foundry Service Key
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/serviceKey
|
||||
- name: cloudFoundry/serviceKeyName
|
||||
- name: cfServiceKey
|
||||
- name: host
|
||||
description: Specifies the host address of the SAP Cloud Platform ABAP Environment system
|
||||
type: string
|
||||
mandatory: false
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
- name: username
|
||||
type: string
|
||||
description: User
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
mandatory: true
|
||||
secret: true
|
||||
- name: password
|
||||
type: string
|
||||
description: Password
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
mandatory: true
|
||||
secret: true
|
||||
- name: phase
|
||||
type: string
|
||||
mandatory: true
|
||||
description: Phase as specified in the build script in the backend system
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: values
|
||||
type: string
|
||||
description: Input values for the build framework
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
mandatory: false
|
||||
- name: downloadAllResultFiles
|
||||
type: bool
|
||||
mandatory: true
|
||||
default: false
|
||||
description: If true, all build artefacts are downloaded
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: downloadResultFilenames
|
||||
type: "[]string"
|
||||
mandatory: false
|
||||
description: Only the specified files are downloaded, downloadAllResultFiles is true, this parameter is ignored
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: publishAllDownloadedResultFiles
|
||||
type: bool
|
||||
mandatory: true
|
||||
default: false
|
||||
description: If true, it publishes all downloaded files
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: publishResultFilenames
|
||||
type: "[]string"
|
||||
mandatory: false
|
||||
description: Only the specified files get published, in case the file was not downloaded before an error occures
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: subDirectoryForDownload
|
||||
type: string
|
||||
mandatory: false
|
||||
description: Target directory to store the downloaded files, {buildID} and {taskID} can be used and will be resolved accordingly
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
- name: filenamePrefixForDownload
|
||||
type: string
|
||||
mandatory: false
|
||||
description: Filename prefix for the downloaded files, {buildID} and {taskID} can be used and will be resolved accordingly
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
- name: treatWarningsAsError
|
||||
type: bool
|
||||
mandatory: true
|
||||
default: false
|
||||
description: If a warrning occures, the step will be set to unstable
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: maxRuntimeInMinutes
|
||||
type: int
|
||||
description: maximal runtime of the step in minutes
|
||||
mandatory: true
|
||||
default: 360
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: pollingIntervallInSeconds
|
||||
type: int
|
||||
description: wait time in seconds till next status request in the backend system
|
||||
mandatory: true
|
||||
default: 60
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: certificateNames
|
||||
type: "[]string"
|
||||
description: certificates for the backend system, this certificates needs to be stored in .pipeline/trustStore
|
||||
mandatory: false
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
- name: cpeValues
|
||||
type: string
|
||||
description: Values taken from the previous step, if a value was also specified in the config file, the value from cpe will be discarded
|
||||
mandatory: false
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: abap/buildValues
|
||||
outputs:
|
||||
resources:
|
||||
- name: commonPipelineEnvironment
|
||||
type: piperEnvironment
|
||||
params:
|
||||
- name: abap/buildValues
|
||||
containers:
|
||||
- name: cf
|
||||
image: ppiper/cf-cli:7
|
@ -113,6 +113,7 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
'abapAddonAssemblyKitRegisterPackages', //implementing new golang pattern without fields
|
||||
'abapAddonAssemblyKitReleasePackages', //implementing new golang pattern without fields
|
||||
'abapAddonAssemblyKitReserveNextPackages', //implementing new golang pattern without fields
|
||||
'abapEnvironmentBuild', //implementing new golang pattern without fields
|
||||
'abapEnvironmentAssemblePackages', //implementing new golang pattern without fields
|
||||
'abapEnvironmentAssembleConfirm', //implementing new golang pattern without fields
|
||||
'abapEnvironmentCheckoutBranch', //implementing new golang pattern without fields
|
||||
|
11
vars/abapEnvironmentBuild.groovy
Normal file
11
vars/abapEnvironmentBuild.groovy
Normal file
@ -0,0 +1,11 @@
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
@Field String METADATA_FILE = 'metadata/abapEnvironmentBuild.yaml'
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
List credentials = [
|
||||
[type: 'usernamePassword', id: 'abapCredentialsId', env: ['PIPER_username', 'PIPER_password']]
|
||||
]
|
||||
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, false, false, true)
|
||||
}
|
Loading…
Reference in New Issue
Block a user