1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-10-30 23:57:50 +02:00

rfc upload (#2533)

* Add RFC upload command
This commit is contained in:
Marcus Holl
2021-06-14 12:36:18 +02:00
committed by GitHub
parent 4250ca8bed
commit fe5ce61d9e
9 changed files with 891 additions and 0 deletions

View File

@@ -75,6 +75,7 @@ func GetAllStepMetadata() map[string]config.StepData {
"transportRequestDocIDFromGit": transportRequestDocIDFromGitMetadata(),
"transportRequestReqIDFromGit": transportRequestReqIDFromGitMetadata(),
"transportRequestUploadCTS": transportRequestUploadCTSMetadata(),
"transportRequestUploadRFC": transportRequestUploadRFCMetadata(),
"transportRequestUploadSOLMAN": transportRequestUploadSOLMANMetadata(),
"uiVeri5ExecuteTests": uiVeri5ExecuteTestsMetadata(),
"vaultRotateSecretId": vaultRotateSecretIdMetadata(),

View File

@@ -136,6 +136,7 @@ func Execute() {
rootCmd.AddCommand(VaultRotateSecretIdCommand())
rootCmd.AddCommand(CheckChangeInDevelopmentCommand())
rootCmd.AddCommand(TransportRequestUploadCTSCommand())
rootCmd.AddCommand(TransportRequestUploadRFCCommand())
rootCmd.AddCommand(NewmanExecuteCommand())
rootCmd.AddCommand(IntegrationArtifactDeployCommand())
rootCmd.AddCommand(TransportRequestUploadSOLMANCommand())

View File

@@ -0,0 +1,85 @@
package cmd
import (
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/transportrequest/rfc"
)
type transportRequestUploadRFCUtils interface {
rfc.Exec
// Add more methods here, or embed additional interfaces, or remove/replace as required.
// The transportRequestUploadRFCUtils interface should be descriptive of your runtime dependencies,
// i.e. include everything you need to be able to mock in tests.
// Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies.
}
type transportRequestUploadRFCUtilsBundle struct {
*command.Command
// Embed more structs as necessary to implement methods or interfaces you add to transportRequestUploadRFCUtils.
// Structs embedded in this way must each have a unique set of methods attached.
// If there is no struct which implements the method you need, attach the method to
// transportRequestUploadRFCUtilsBundle and forward to the implementation of the dependency.
}
func newTransportRequestUploadRFCUtils() transportRequestUploadRFCUtils {
utils := transportRequestUploadRFCUtilsBundle{
Command: &command.Command{},
}
// Reroute command output to logging framework
utils.Stdout(log.Writer())
utils.Stderr(log.Writer())
return &utils
}
func transportRequestUploadRFC(config transportRequestUploadRFCOptions, telemetryData *telemetry.CustomData) {
// Utils can be used wherever the command.ExecRunner interface is expected.
// It can also be used for example as a mavenExecRunner.
utils := newTransportRequestUploadRFCUtils()
action := rfc.UploadAction{}
// For HTTP calls import piperhttp "github.com/SAP/jenkins-library/pkg/http"
// and use a &piperhttp.Client{} in a custom system
// Example: step checkmarxExecuteScan.go
// Error situations should be bubbled up until they reach the line below which will then stop execution
// through the log.Entry().Fatal() call leading to an os.Exit(1) in the end.
err := runTransportRequestUploadRFC(&config, &action, telemetryData, utils)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runTransportRequestUploadRFC(config *transportRequestUploadRFCOptions, action rfc.Upload, telemetryData *telemetry.CustomData, cmd rfc.Exec) error {
action.WithConnection(
rfc.Connection{
Endpoint: config.Endpoint,
Client: config.Client,
Instance: config.Instance,
User: config.Username,
Password: config.Password,
},
)
action.WithApplication(
rfc.Application{
Name: config.ApplicationName,
Description: config.ApplicationDescription,
AbapPackage: config.AbapPackage,
},
)
action.WithConfiguration(
rfc.UploadConfig{
AcceptUnixStyleEndOfLine: config.AcceptUnixStyleLineEndings,
CodePage: config.CodePage,
FailUploadOnWarning: config.FailUploadOnWarning,
Verbose: GeneralConfig.Verbose,
},
)
action.WithTransportRequestID(config.TransportRequestID)
action.WithApplicationURL(config.ApplicationURL)
return action.Perform(cmd)
}

View File

@@ -0,0 +1,260 @@
// Code generated by piper's step-generator. DO NOT EDIT.
package cmd
import (
"fmt"
"os"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/splunk"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/spf13/cobra"
)
type transportRequestUploadRFCOptions struct {
Endpoint string `json:"endpoint,omitempty"`
Client string `json:"client,omitempty"`
Instance string `json:"instance,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
ApplicationName string `json:"applicationName,omitempty"`
ApplicationDescription string `json:"applicationDescription,omitempty"`
AbapPackage string `json:"abapPackage,omitempty"`
ApplicationURL string `json:"applicationUrl,omitempty"`
CodePage string `json:"codePage,omitempty"`
AcceptUnixStyleLineEndings bool `json:"acceptUnixStyleLineEndings,omitempty"`
FailUploadOnWarning bool `json:"failUploadOnWarning,omitempty"`
TransportRequestID string `json:"transportRequestId,omitempty"`
}
// TransportRequestUploadRFCCommand Uploads content to a transport request
func TransportRequestUploadRFCCommand() *cobra.Command {
const STEP_NAME = "transportRequestUploadRFC"
metadata := transportRequestUploadRFCMetadata()
var stepConfig transportRequestUploadRFCOptions
var startTime time.Time
var logCollector *log.CollectorHook
var createTransportRequestUploadRFCCmd = &cobra.Command{
Use: STEP_NAME,
Short: "Uploads content to a transport request",
Long: `Uploads content to a transport request.`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
startTime = time.Now()
log.SetStepName(STEP_NAME)
log.SetVerbose(GeneralConfig.Verbose)
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 {
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
log.RegisterHook(logCollector)
}
return nil
},
Run: func(_ *cobra.Command, _ []string) {
telemetryData := telemetry.CustomData{}
telemetryData.ErrorCode = "1"
handler := func() {
config.RemoveVaultSecretFiles()
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
telemetryData.ErrorCategory = log.GetErrorCategory().String()
telemetry.Send(&telemetryData)
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunk.Send(&telemetryData, logCollector)
}
}
log.DeferExitHandler(handler)
defer handler()
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunk.Initialize(GeneralConfig.CorrelationID,
GeneralConfig.HookConfig.SplunkConfig.Dsn,
GeneralConfig.HookConfig.SplunkConfig.Token,
GeneralConfig.HookConfig.SplunkConfig.Index,
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
}
transportRequestUploadRFC(stepConfig, &telemetryData)
telemetryData.ErrorCode = "0"
log.Entry().Info("SUCCESS")
},
}
addTransportRequestUploadRFCFlags(createTransportRequestUploadRFCCmd, &stepConfig)
return createTransportRequestUploadRFCCmd
}
func addTransportRequestUploadRFCFlags(cmd *cobra.Command, stepConfig *transportRequestUploadRFCOptions) {
cmd.Flags().StringVar(&stepConfig.Endpoint, "endpoint", os.Getenv("PIPER_endpoint"), "Service endpoint")
cmd.Flags().StringVar(&stepConfig.Client, "client", os.Getenv("PIPER_client"), "AS ABAP client number")
cmd.Flags().StringVar(&stepConfig.Instance, "instance", os.Getenv("PIPER_instance"), "AS ABAP instance number")
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "Deploy user")
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for the deploy user")
cmd.Flags().StringVar(&stepConfig.ApplicationName, "applicationName", os.Getenv("PIPER_applicationName"), "Name of the application.")
cmd.Flags().StringVar(&stepConfig.ApplicationDescription, "applicationDescription", os.Getenv("PIPER_applicationDescription"), "Description of the application.")
cmd.Flags().StringVar(&stepConfig.AbapPackage, "abapPackage", os.Getenv("PIPER_abapPackage"), "ABAP package name of your application")
cmd.Flags().StringVar(&stepConfig.ApplicationURL, "applicationUrl", os.Getenv("PIPER_applicationUrl"), "URL where to find the UI5 package to upload to the transport request")
cmd.Flags().StringVar(&stepConfig.CodePage, "codePage", `UTF-8`, "Code page")
cmd.Flags().BoolVar(&stepConfig.AcceptUnixStyleLineEndings, "acceptUnixStyleLineEndings", true, "If unix style line endings should be accepted")
cmd.Flags().BoolVar(&stepConfig.FailUploadOnWarning, "failUploadOnWarning", true, "If the upload should fail in case the log contains warnings")
cmd.Flags().StringVar(&stepConfig.TransportRequestID, "transportRequestId", os.Getenv("PIPER_transportRequestId"), "Transport request id")
cmd.MarkFlagRequired("endpoint")
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("password")
cmd.MarkFlagRequired("applicationName")
cmd.MarkFlagRequired("abapPackage")
cmd.MarkFlagRequired("applicationUrl")
cmd.MarkFlagRequired("abapPackage")
cmd.MarkFlagRequired("transportRequestId")
}
// retrieve step metadata
func transportRequestUploadRFCMetadata() config.StepData {
var theMetaData = config.StepData{
Metadata: config.StepMetadata{
Name: "transportRequestUploadRFC",
Aliases: []config.Alias{{Name: "transportRequestUploadFile", Deprecated: false}},
Description: "Uploads content to a transport request",
},
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "endpoint",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{{Name: "changeManagement/endpoint"}},
},
{
Name: "client",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "changeManagement/rfc/developmentClient"}},
},
{
Name: "instance",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "changeManagement/rfc/developmentInstance"}},
},
{
Name: "username",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "password",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "applicationName",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "applicationDescription",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "abapPackage",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "applicationUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "abapPackage",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "codePage",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "acceptUnixStyleLineEndings",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "failUploadOnWarning",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{{Name: "failOnWarning"}},
},
{
Name: "transportRequestId",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
},
},
},
}
return theMetaData
}

View File

@@ -0,0 +1,17 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTransportRequestUploadRFCCommand(t *testing.T) {
t.Parallel()
testCmd := TransportRequestUploadRFCCommand()
// only high level testing performed - details are tested in step generation procedure
assert.Equal(t, "transportRequestUploadRFC", testCmd.Use, "command name incorrect")
}

View File

@@ -0,0 +1,110 @@
package cmd
import (
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/transportrequest/rfc"
"github.com/stretchr/testify/assert"
"testing"
)
type transportRequestUploadRFCMockUtils struct {
*mock.ExecMockRunner
}
func newTransportRequestUploadRFCTestsUtils() transportRequestUploadRFCMockUtils {
utils := transportRequestUploadRFCMockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
}
return utils
}
type uploadMock struct {
received rfc.UploadAction
uploadCalled bool
}
// WithApplicationURL The location of the deployable
func (m *uploadMock) WithApplicationURL(z string) {
m.received.ApplicationURL = z
}
// WithTransportRequestID The transport request ID for the upload
func (m *uploadMock) WithTransportRequestID(t string) {
m.received.TransportRequestID = t
}
// WithApplication Everything we need to know about the application
func (m *uploadMock) WithApplication(a rfc.Application) {
m.received.Application = a
}
// WithConfiguration Everything we need to know in order to perform the upload
func (m *uploadMock) WithConfiguration(c rfc.UploadConfig) {
m.received.Configuration = c
}
// WithConnection Everything we need to know about the connection
func (m *uploadMock) WithConnection(c rfc.Connection) {
m.received.Connection = c
}
func (m *uploadMock) Perform(exec rfc.Exec) error {
m.uploadCalled = true
return nil
}
func TestRunTransportRequestUploadRFC(t *testing.T) {
t.Parallel()
config := transportRequestUploadRFCOptions{
Endpoint: "https://my.abap.server",
Client: "001",
Instance: "00",
Username: "me",
Password: "******",
ApplicationName: "MyApp",
ApplicationDescription: "Lorem impsum",
AbapPackage: "XX",
ApplicationURL: "http://example.org/myDeployable.zip",
CodePage: "UTF-8",
AcceptUnixStyleLineEndings: true,
FailUploadOnWarning: true,
TransportRequestID: "XXXK12345678",
}
utils := newTransportRequestUploadRFCTestsUtils()
mock := uploadMock{}
err := runTransportRequestUploadRFC(&config, &mock, nil, utils)
if assert.NoError(t, err) {
t.Run("upload triggered", func(t *testing.T) {
assert.True(t, mock.uploadCalled)
})
t.Run("parameters has been marshalled", func(t *testing.T) {
assert.Equal(t, rfc.UploadAction{
Connection: rfc.Connection{
Endpoint: "https://my.abap.server",
Client: "001",
Instance: "00",
User: "me",
Password: "******",
},
Application: rfc.Application{
Name: "MyApp",
Description: "Lorem impsum",
AbapPackage: "XX",
},
Configuration: rfc.UploadConfig{
AcceptUnixStyleEndOfLine: true,
CodePage: "UTF-8",
FailUploadOnWarning: true,
Verbose: false, // comes from general config
},
TransportRequestID: "XXXK12345678",
ApplicationURL: "http://example.org/myDeployable.zip",
}, mock.received)
})
}
}

View File

@@ -0,0 +1,158 @@
package rfc
import (
"fmt"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/config/validation"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/pkg/errors"
"strconv"
)
const (
eq = "="
)
// Exec Everything we need for calling an executable
type Exec interface {
command.ExecRunner
GetExitCode() int
}
// Upload ...
type Upload interface {
Perform(Exec) error
WithConnection(Connection)
WithConfiguration(UploadConfig)
WithApplication(Application)
WithTransportRequestID(string)
WithApplicationURL(string)
}
// Connection Everything we need for connecting to the ABAP system
type Connection struct {
// The endpoint in for form <protocol>://<host>:<port>, no path
Endpoint string
// The ABAP client, like e.g. "001"
Client string
// The ABAP instance, like e.g. "DEV", "QA"
Instance string
User string
Password string
}
// Application Application specific properties
type Application struct {
Name string
Description string
AbapPackage string
}
// UploadConfig additional configuration properties
type UploadConfig struct {
AcceptUnixStyleEndOfLine bool
CodePage string
FailUploadOnWarning bool
Verbose bool
}
// UploadAction Collects all the properties we need for the deployment
type UploadAction struct {
Connection Connection
Application Application
Configuration UploadConfig
TransportRequestID string
ApplicationURL string
}
// WithApplicationURL The location of the deployable
func (action *UploadAction) WithApplicationURL(z string) {
action.ApplicationURL = z
}
// WithTransportRequestID The transport request ID for the upload
func (action *UploadAction) WithTransportRequestID(t string) {
action.TransportRequestID = t
}
// WithApplication Everything we need to know about the application
func (action *UploadAction) WithApplication(a Application) {
action.Application = a
}
// WithConfiguration Everything we need to know in order to perform the upload
func (action *UploadAction) WithConfiguration(c UploadConfig) {
action.Configuration = c
}
// WithConnection Everything we need to know about the connection
func (action *UploadAction) WithConnection(c Connection) {
action.Connection = c
}
// Perform Performs the upload
func (action *UploadAction) Perform(command Exec) error {
log.Entry().Infof("Deploying artifact '%s' to '%s', client: '%s', instance: '%s'.",
action.ApplicationURL, action.Connection.Endpoint, action.Connection.Client, action.Connection.Instance,
)
parametersWithMissingValues, err := validation.FindEmptyStringsInConfigStruct(*action)
if err != nil {
return fmt.Errorf("invalid configuration parameters detected. SOLMAN upload parameter may be missing : %w", err)
}
if len(parametersWithMissingValues) != 0 {
return fmt.Errorf("Cannot perform artifact upload. The following parameters are not available %s", parametersWithMissingValues)
}
command.SetEnv([]string{
"ABAP_DEVELOPMENT_SERVER" + eq + action.Connection.Endpoint,
"ABAP_DEVELOPMENT_USER" + eq + action.Connection.User,
"ABAP_DEVELOPMENT_PASSWORD" + eq + action.Connection.Password,
"ABAP_DEVELOPMENT_INSTANCE" + eq + action.Connection.Instance,
"ABAP_DEVELOPMENT_CLIENT" + eq + action.Connection.Client,
"ABAP_APPLICATION_NAME" + eq + action.Application.Name,
"ABAP_APPLICATION_DESC" + eq + action.Application.Description,
"ABAP_PACKAGE" + eq + action.Application.AbapPackage,
"ZIP_FILE_URL" + eq + action.ApplicationURL,
"CODE_PAGE" + eq + action.Configuration.CodePage,
"ABAP_ACCEPT_UNIX_STYLE_EOL" + eq + toAbapBool(action.Configuration.AcceptUnixStyleEndOfLine),
"FAIL_UPLOAD_ON_WARNING" + eq + strconv.FormatBool(action.Configuration.FailUploadOnWarning),
"VERBOSE" + eq + strconv.FormatBool(action.Configuration.Verbose),
})
err = command.RunExecutable("cts", fmt.Sprintf("uploadToABAP:%s", action.TransportRequestID))
exitCode := command.GetExitCode()
if exitCode != 0 {
message := fmt.Sprintf("upload command returned with exit code '%d'", exitCode)
if err != nil {
// Using the wrapping here is to some extend an abuse, since it is not really
// error chaining (the other error is not necessaryly a "predecessor" of this one).
// But it is a pragmatic approach for not loosing information for trouble shooting. There
// is no possibility to have something like suppressed errors.
err = errors.Wrap(err, message)
} else {
err = errors.New(message)
}
}
if err == nil {
log.Entry().Infof("Deploying artifact '%s' to '%s', client: '%s', instance: '%s' succeeded.",
action.ApplicationURL, action.Connection.Endpoint, action.Connection.Client, action.Connection.Instance,
)
} else {
log.Entry().Warnf("Deploying artifact '%s' to '%s', client: '%s', instance: '%s' failed.",
action.ApplicationURL, action.Connection.Endpoint, action.Connection.Client, action.Connection.Instance,
)
}
return errors.Wrap(err, "cannot upload artifact")
}
func toAbapBool(b bool) string {
abapBool := "-"
if b {
abapBool = "X"
}
return abapBool
}

View File

@@ -0,0 +1,115 @@
package rfc
import (
"fmt"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/stretchr/testify/assert"
"testing"
)
func TestUploadRFC(t *testing.T) {
defaultUploadAction := UploadAction{
Connection: Connection{
Endpoint: "https://example.org/rfc",
Client: "001",
Instance: "DEV",
User: "me",
Password: "******",
},
Application: Application{
Name: "myApp",
Description: "The description",
AbapPackage: "YYY",
},
Configuration: UploadConfig{
AcceptUnixStyleEndOfLine: true,
CodePage: "UTF-8",
FailUploadOnWarning: true,
Verbose: true,
},
TransportRequestID: "123456",
ApplicationURL: "https://localhost:8081/myDeployable.zip",
}
t.Run("straight forward", func(t *testing.T) {
exec := mock.ExecMockRunner{}
upload := defaultUploadAction
err := upload.Perform(&exec)
if assert.NoError(t, err) {
assert.Equal(t, exec.Calls, []mock.ExecCall{mock.ExecCall{Exec: "cts", Params: []string{"uploadToABAP:123456"}}})
assert.Subset(t, []string{
"ABAP_DEVELOPMENT_SERVER=https://example.org/rfc",
"ABAP_DEVELOPMENT_USER=me",
"ABAP_DEVELOPMENT_PASSWORD=******",
"ABAP_DEVELOPMENT_INSTANCE=DEV",
"ABAP_DEVELOPMENT_CLIENT=001",
"ABAP_APPLICATION_NAME=myApp",
"ABAP_APPLICATION_DESC=The description",
"ABAP_PACKAGE=YYY",
"ZIP_FILE_URL=https://localhost:8081/myDeployable.zip",
"CODE_PAGE=UTF-8",
"ABAP_ACCEPT_UNIX_STYLE_EOL=X",
"FAIL_UPLOAD_ON_WARNING=true",
"VERBOSE=true",
}, exec.Env)
assert.Len(t, exec.Env, 13)
}
})
t.Run("incomplete config", func(t *testing.T) {
exec := mock.ExecMockRunner{}
upload := defaultUploadAction
upload.Connection.Endpoint = ""
upload.Application.AbapPackage = ""
err := upload.Perform(&exec)
if assert.Error(t, err) {
// Don't want to rely on the order, hence not checking for the full string ...
assert.Contains(t, err.Error(), "Cannot perform artifact upload. The following parameters are not available")
assert.Contains(t, err.Error(), "Connection.Endpoint")
assert.Contains(t, err.Error(), "Application.AbapPackage")
}
})
t.Run("invocation of cts tooling fails", func(t *testing.T) {
t.Run("error raised", func(t *testing.T) {
exec := mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"cts.*": fmt.Errorf("generic failure")}}
upload := defaultUploadAction
err := upload.Perform(&exec)
assert.EqualError(t, err, "cannot upload artifact: generic failure")
})
t.Run("return code not zero", func(t *testing.T) {
exec := mock.ExecMockRunner{ExitCode: 42}
upload := defaultUploadAction
err := upload.Perform(&exec)
assert.EqualError(t, err, "cannot upload artifact: upload command returned with exit code '42'")
})
})
}
func TestTheAbapBool(t *testing.T) {
t.Run("true", func(t *testing.T) {
assert.Equal(t, "X", toAbapBool(true))
})
t.Run("false", func(t *testing.T) {
assert.Equal(t, "-", toAbapBool(false))
})
}

View File

@@ -0,0 +1,144 @@
metadata:
name: transportRequestUploadRFC
aliases:
- name: transportRequestUploadFile
description: "Uploads content to a transport request"
longDescription: |
Uploads content to a transport request.
spec:
inputs:
secrets:
- name: uploadCredentialsId
description: Jenkins 'Username with password' credentials ID containing user and password to authenticate against the ABAP backend.
type: jenkins
aliases:
- name: changeManagement/credentialsId
params:
- name: endpoint
type: string
mandatory: true
description: "Service endpoint"
aliases:
- name: changeManagement/endpoint
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: client
type: string
aliases:
- name: changeManagement/rfc/developmentClient
description: "AS ABAP client number"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: instance
type: string
aliases:
- name: changeManagement/rfc/developmentInstance
description: "AS ABAP instance number"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: username
type: string
mandatory: true
description: "Deploy user"
secret: true
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: password
type: string
mandatory: true
description: "Password for the deploy user"
secret: true
scope:
- PARAMETERS
- name: applicationName
type: string
mandatory: true
description: "Name of the application."
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: applicationDescription
type: string
mandatory: false
description: "Description of the application."
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: abapPackage
type: string
mandatory: true
description: "ABAP package name of your application"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: applicationUrl
type: string
mandatory: true
description: "URL where to find the UI5 package to upload to the transport request"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: abapPackage
type: string
mandatory: true
description: "ABAP package name of your application"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: codePage
type: string
default: "UTF-8"
description: "Code page"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: acceptUnixStyleLineEndings
type: bool
default: true
description: "If unix style line endings should be accepted"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: failUploadOnWarning
type: bool
default: true
aliases:
- name: failOnWarning
description: "If the upload should fail in case the log contains warnings"
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
- name: transportRequestId
type: string
mandatory: true
description: "Transport request id"
scope:
- PARAMETERS