github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/cmd/shellExecute.go (about)

     1  package cmd
     2  
     3  import (
     4  	"fmt"
     5  	"os/exec"
     6  	"strings"
     7  
     8  	"github.com/pkg/errors"
     9  
    10  	"github.com/SAP/jenkins-library/pkg/command"
    11  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    12  	"github.com/SAP/jenkins-library/pkg/log"
    13  	"github.com/SAP/jenkins-library/pkg/piperutils"
    14  	"github.com/SAP/jenkins-library/pkg/telemetry"
    15  )
    16  
    17  type shellExecuteUtils interface {
    18  	command.ExecRunner
    19  	piperutils.FileUtils
    20  	piperhttp.Downloader
    21  }
    22  
    23  type shellExecuteUtilsBundle struct {
    24  	*command.Command
    25  	*piperutils.Files
    26  	*piperhttp.Client
    27  }
    28  
    29  const (
    30  	argumentDelimter = ","
    31  )
    32  
    33  func newShellExecuteUtils() shellExecuteUtils {
    34  	utils := shellExecuteUtilsBundle{
    35  		Command: &command.Command{},
    36  		Files:   &piperutils.Files{},
    37  		Client:  &piperhttp.Client{},
    38  	}
    39  	utils.Stdout(log.Writer())
    40  	utils.Stderr(log.Writer())
    41  	return &utils
    42  }
    43  
    44  func shellExecute(config shellExecuteOptions, telemetryData *telemetry.CustomData) {
    45  	utils := newShellExecuteUtils()
    46  
    47  	err := runShellExecute(&config, telemetryData, utils)
    48  	if err != nil {
    49  		log.Entry().WithError(err).Fatal("step execution failed")
    50  	}
    51  }
    52  
    53  func runShellExecute(config *shellExecuteOptions, telemetryData *telemetry.CustomData, utils shellExecuteUtils) error {
    54  	// check input data
    55  	// example for script: sources: ["./script.sh"]
    56  	for position, source := range config.Sources {
    57  
    58  		if strings.Contains(source, "https") {
    59  			scriptLocation, err := piperhttp.DownloadExecutable(config.GithubToken, utils, utils, source)
    60  			if err != nil {
    61  				return errors.Wrapf(err, "script download error")
    62  			}
    63  			source = scriptLocation
    64  		}
    65  		// check if the script is physically present
    66  		exists, err := utils.FileExists(source)
    67  		if err != nil {
    68  			log.Entry().WithError(err).Error("failed to check for defined script")
    69  			return fmt.Errorf("failed to check for defined script: %w", err)
    70  		}
    71  		if !exists {
    72  			log.Entry().WithError(err).Errorf("the script '%v' could not be found: %v", source, err)
    73  			return fmt.Errorf("the script '%v' could not be found", source)
    74  		}
    75  
    76  		args := []string{}
    77  		if len(config.ScriptArguments) > 0 && isArgumentAtPosition(config.ScriptArguments, position) {
    78  			args = strings.Split(config.ScriptArguments[position], argumentDelimter)
    79  		}
    80  
    81  		log.Entry().Info("starting running script:", source)
    82  
    83  		err = utils.RunExecutable(source, args...)
    84  		if err != nil {
    85  			log.Entry().Errorln("starting running script:", source)
    86  		}
    87  		// handle exit code
    88  		if ee, ok := err.(*exec.ExitError); ok {
    89  			switch ee.ExitCode() {
    90  			case 0:
    91  				// success
    92  				return nil
    93  			case 1:
    94  				return errors.Wrap(err, "an error occurred while executing the script")
    95  			default:
    96  				// exit code 2 or >2 - unstable
    97  				return errors.Wrap(err, "script execution unstable or something went wrong")
    98  			}
    99  		} else if err != nil {
   100  			return errors.Wrap(err, "script execution error occurred")
   101  		}
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  func isArgumentAtPosition(scriptArguments []string, index int) bool {
   108  	return ((len(scriptArguments) > index) && scriptArguments[index] != "")
   109  }