github.com/jaylevin/jenkins-library@v1.230.4/cmd/shellExecute.go (about)

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