You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +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:
		| @@ -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 { | ||||
|   | ||||
| @@ -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{ | ||||
|   | ||||
| @@ -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) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user