1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

feat (shellExecute) extend shellExecute to accept script arguments (#3823)

* adding arguments

* splitting strings into args and checking position

* addtional check on adding arguments

* unit testing

* refactoring code

* unit test clean up

* add unit test for multiple params in multiple scripts

* unit test name

Co-authored-by: anilkeshav27 <you@example.com>
This commit is contained in:
Anil Keshav 2022-06-10 16:10:46 +02:00 committed by GitHub
parent 5edb0d2566
commit 011ba40f87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 14 deletions

View File

@ -51,7 +51,7 @@ func shellExecute(config shellExecuteOptions, telemetryData *telemetry.CustomDat
func runShellExecute(config *shellExecuteOptions, telemetryData *telemetry.CustomData, utils shellExecuteUtils) error {
// check input data
// example for script: sources: ["./script.sh"]
for _, source := range config.Sources {
for position, source := range config.Sources {
if strings.Contains(source, "https") {
scriptLocation, err := downloadScript(config, utils, source)
@ -70,9 +70,15 @@ func runShellExecute(config *shellExecuteOptions, telemetryData *telemetry.Custo
log.Entry().WithError(err).Errorf("the script '%v' could not be found: %v", source, err)
return fmt.Errorf("the script '%v' could not be found", source)
}
args := []string{}
if len(config.ScriptArguments) > 0 && isArgumentAtPosition(config.ScriptArguments, position) {
args = strings.Split(config.ScriptArguments[position], " ")
}
log.Entry().Info("starting running script:", source)
err = utils.RunExecutable(source)
err = utils.RunExecutable(source, args...)
if err != nil {
log.Entry().Errorln("starting running script:", source)
}
@ -96,6 +102,10 @@ func runShellExecute(config *shellExecuteOptions, telemetryData *telemetry.Custo
return nil
}
func isArgumentAtPosition(scriptArguments []string, index int) bool {
return ((len(scriptArguments) > index) && scriptArguments[index] != "")
}
func downloadScript(config *shellExecuteOptions, utils shellExecuteUtils, url string) (string, error) {
header := http.Header{}
if len(config.GithubToken) > 0 {

View File

@ -16,8 +16,9 @@ import (
)
type shellExecuteOptions struct {
Sources []string `json:"sources,omitempty"`
GithubToken string `json:"githubToken,omitempty"`
Sources []string `json:"sources,omitempty"`
GithubToken string `json:"githubToken,omitempty"`
ScriptArguments []string `json:"scriptArguments,omitempty"`
}
// ShellExecuteCommand Step executes defined script
@ -112,6 +113,7 @@ func ShellExecuteCommand() *cobra.Command {
func addShellExecuteFlags(cmd *cobra.Command, stepConfig *shellExecuteOptions) {
cmd.Flags().StringSliceVar(&stepConfig.Sources, "sources", []string{}, "Scripts paths that must be present in the current workspace or https links to scripts. Only https urls from github are allowed and must be in the format :https://{githubBaseurl}/api/v3/repos/{owner}/{repository}/contents/{path to script} Authentication for the download is only supported via the 'githubToken' param. Make sure the script has the necessary execute permissions.")
cmd.Flags().StringVar(&stepConfig.GithubToken, "githubToken", os.Getenv("PIPER_githubToken"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line")
cmd.Flags().StringSliceVar(&stepConfig.ScriptArguments, "scriptArguments", []string{}, "scriptArguments that are needed to be passed to scripts. the scriptArguments list is a flat list and has a positional relationship to the `sources` param. For e.g. The scriptArguments string at position 1 will be considered as the argument(s) for script at position 1 in `sources` list")
}
@ -158,6 +160,15 @@ func shellExecuteMetadata() config.StepData {
Aliases: []config.Alias{{Name: "access_token"}},
Default: os.Getenv("PIPER_githubToken"),
},
{
Name: "scriptArguments",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{},
Default: []string{},
},
},
},
Containers: []config.Container{

View File

@ -73,23 +73,21 @@ func TestRunShellExecute(t *testing.T) {
assert.EqualError(t, err, "the script 'path/to/script.sh' could not be found")
})
t.Run("success case - script is present", func(t *testing.T) {
o := &shellExecuteOptions{}
u := newShellExecuteTestsUtils()
err := runShellExecute(o, nil, u)
assert.NoError(t, err)
})
t.Run("success case - script run successfully", func(t *testing.T) {
o := &shellExecuteOptions{}
o := &shellExecuteOptions{
Sources: []string{"path/script.sh"},
}
u := newShellExecuteTestsUtils()
u.AddFile("path/script.sh", []byte(`echo dummy`))
err := runShellExecute(o, nil, u)
assert.Equal(t, "path/script.sh", u.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{}, u.ExecMockRunner.Calls[0].Params)
assert.NoError(t, err)
})
t.Run("success case - download script header", func(t *testing.T) {
t.Run("success case - download script header gets added", func(t *testing.T) {
o := &shellExecuteOptions{
Sources: []string{"https://myScriptLocation/myScript.sh"},
GithubToken: "dummy@12345",
@ -100,4 +98,42 @@ func TestRunShellExecute(t *testing.T) {
assert.Equal(t, http.Header{"Accept": []string{"application/vnd.github.v3.raw"}, "Authorization": []string{"Token dummy@12345"}}, u.header)
})
t.Run("success case - single positional script arguments gets added to the correct script", func(t *testing.T) {
o := &shellExecuteOptions{
Sources: []string{"path1/script1.sh", "path2/script2.sh"},
ScriptArguments: []string{"arg1", "arg2"},
}
u := newShellExecuteTestsUtils()
u.AddFile("path1/script1.sh", []byte(`echo dummy1`))
u.AddFile("path2/script2.sh", []byte(`echo dummy2`))
err := runShellExecute(o, nil, u)
assert.Equal(t, "path1/script1.sh", u.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"arg1"}, u.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "path2/script2.sh", u.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"arg2"}, u.ExecMockRunner.Calls[1].Params)
assert.NoError(t, err)
})
t.Run("success case - multiple positional script arguments gets added to the correct script", func(t *testing.T) {
o := &shellExecuteOptions{
Sources: []string{"path1/script1.sh", "path2/script2.sh"},
ScriptArguments: []string{"arg1 arg2", "arg3 arg4"},
}
u := newShellExecuteTestsUtils()
u.AddFile("path1/script1.sh", []byte(`echo dummy1`))
u.AddFile("path2/script2.sh", []byte(`echo dummy2`))
err := runShellExecute(o, nil, u)
assert.Equal(t, "path1/script1.sh", u.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"arg1", "arg2"}, u.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "path2/script2.sh", u.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"arg3", "arg4"}, u.ExecMockRunner.Calls[1].Params)
assert.NoError(t, err)
})
}

View File

@ -36,6 +36,15 @@ spec:
- type: vaultSecret
default: github
name: githubVaultSecretName
- name: scriptArguments
type: "[]string"
scope:
- PARAMETERS
- STAGES
- STEPS
description: scriptArguments that are needed to be passed to scripts. the scriptArguments list is a flat list and has a positional relationship to the `sources` param.
For e.g. The scriptArguments string at position 1 will be considered as the argument(s) for script at position 1 in `sources` list
mandatory: false
containers:
- name: shell
image: node:lts-stretch