2021-11-19 11:05:39 +02:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2021-12-13 13:31:31 +02:00
|
|
|
"fmt"
|
2022-03-31 18:18:20 +02:00
|
|
|
"net/http"
|
2021-11-19 11:05:39 +02:00
|
|
|
"os/exec"
|
2022-03-31 18:18:20 +02:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2021-11-19 11:05:39 +02:00
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
|
|
|
"github.com/SAP/jenkins-library/pkg/command"
|
2022-03-31 18:18:20 +02:00
|
|
|
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
2021-11-19 11:05:39 +02:00
|
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
|
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
|
|
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
|
|
|
)
|
|
|
|
|
|
|
|
type shellExecuteUtils interface {
|
|
|
|
command.ExecRunner
|
2021-12-13 13:31:31 +02:00
|
|
|
piperutils.FileUtils
|
2022-03-31 18:18:20 +02:00
|
|
|
piperhttp.Downloader
|
2021-11-19 11:05:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type shellExecuteUtilsBundle struct {
|
|
|
|
*command.Command
|
|
|
|
*piperutils.Files
|
2022-03-31 18:18:20 +02:00
|
|
|
*piperhttp.Client
|
2021-11-19 11:05:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func newShellExecuteUtils() shellExecuteUtils {
|
|
|
|
utils := shellExecuteUtilsBundle{
|
|
|
|
Command: &command.Command{},
|
|
|
|
Files: &piperutils.Files{},
|
2022-03-31 18:18:20 +02:00
|
|
|
Client: &piperhttp.Client{},
|
2021-11-19 11:05:39 +02:00
|
|
|
}
|
|
|
|
utils.Stdout(log.Writer())
|
|
|
|
utils.Stderr(log.Writer())
|
|
|
|
return &utils
|
|
|
|
}
|
|
|
|
|
|
|
|
func shellExecute(config shellExecuteOptions, telemetryData *telemetry.CustomData) {
|
|
|
|
utils := newShellExecuteUtils()
|
|
|
|
|
2021-12-13 13:31:31 +02:00
|
|
|
err := runShellExecute(&config, telemetryData, utils)
|
2021-11-19 11:05:39 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Entry().WithError(err).Fatal("step execution failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-13 13:31:31 +02:00
|
|
|
func runShellExecute(config *shellExecuteOptions, telemetryData *telemetry.CustomData, utils shellExecuteUtils) error {
|
2021-11-19 11:05:39 +02:00
|
|
|
// check input data
|
|
|
|
// example for script: sources: ["./script.sh"]
|
2022-06-10 16:10:46 +02:00
|
|
|
for position, source := range config.Sources {
|
2022-03-31 18:18:20 +02:00
|
|
|
|
|
|
|
if strings.Contains(source, "https") {
|
|
|
|
scriptLocation, err := downloadScript(config, utils, source)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "script download error")
|
|
|
|
}
|
|
|
|
source = scriptLocation
|
|
|
|
}
|
2021-12-13 13:31:31 +02:00
|
|
|
// check if the script is physically present
|
|
|
|
exists, err := utils.FileExists(source)
|
2021-11-19 11:05:39 +02:00
|
|
|
if err != nil {
|
2021-12-13 13:31:31 +02:00
|
|
|
log.Entry().WithError(err).Error("failed to check for defined script")
|
|
|
|
return fmt.Errorf("failed to check for defined script: %w", err)
|
2021-11-19 11:05:39 +02:00
|
|
|
}
|
2021-12-13 13:31:31 +02:00
|
|
|
if !exists {
|
|
|
|
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)
|
|
|
|
}
|
2022-06-10 16:10:46 +02:00
|
|
|
|
|
|
|
args := []string{}
|
|
|
|
if len(config.ScriptArguments) > 0 && isArgumentAtPosition(config.ScriptArguments, position) {
|
|
|
|
args = strings.Split(config.ScriptArguments[position], " ")
|
|
|
|
}
|
|
|
|
|
2021-12-13 13:31:31 +02:00
|
|
|
log.Entry().Info("starting running script:", source)
|
2022-03-31 18:18:20 +02:00
|
|
|
|
2022-06-10 16:10:46 +02:00
|
|
|
err = utils.RunExecutable(source, args...)
|
2021-11-19 11:05:39 +02:00
|
|
|
if err != nil {
|
2021-12-13 13:31:31 +02:00
|
|
|
log.Entry().Errorln("starting running script:", source)
|
2021-11-19 11:05:39 +02:00
|
|
|
}
|
2021-12-13 13:31:31 +02:00
|
|
|
// handle exit code
|
2021-11-19 11:05:39 +02:00
|
|
|
if ee, ok := err.(*exec.ExitError); ok {
|
|
|
|
switch ee.ExitCode() {
|
|
|
|
case 0:
|
|
|
|
// success
|
|
|
|
return nil
|
|
|
|
case 1:
|
|
|
|
return errors.Wrap(err, "an error occurred while executing the script")
|
|
|
|
default:
|
|
|
|
// exit code 2 or >2 - unstable
|
|
|
|
return errors.Wrap(err, "script execution unstable or something went wrong")
|
|
|
|
}
|
|
|
|
} else if err != nil {
|
|
|
|
return errors.Wrap(err, "script execution error occurred")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2022-03-31 18:18:20 +02:00
|
|
|
|
2022-06-10 16:10:46 +02:00
|
|
|
func isArgumentAtPosition(scriptArguments []string, index int) bool {
|
|
|
|
return ((len(scriptArguments) > index) && scriptArguments[index] != "")
|
|
|
|
}
|
|
|
|
|
2022-03-31 18:18:20 +02:00
|
|
|
func downloadScript(config *shellExecuteOptions, utils shellExecuteUtils, url string) (string, error) {
|
|
|
|
header := http.Header{}
|
|
|
|
if len(config.GithubToken) > 0 {
|
|
|
|
header = http.Header{"Authorization": []string{"Token " + config.GithubToken}}
|
|
|
|
header.Set("Accept", "application/vnd.github.v3.raw")
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Entry().Infof("downloading script : %v", url)
|
|
|
|
fileNameParts := strings.Split(url, "/")
|
|
|
|
fileName := fileNameParts[len(fileNameParts)-1]
|
|
|
|
err := utils.DownloadFile(url, filepath.Join(".pipeline", fileName), header, []*http.Cookie{})
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrapf(err, "unable to download script from %v", url)
|
|
|
|
}
|
|
|
|
log.Entry().Infof("downloaded script %v successfully", url)
|
|
|
|
err = fileUtils.Chmod(filepath.Join(".pipeline", fileName), 0555)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrapf(err, "unable to change script permission for %v", filepath.Join(".pipeline", fileName))
|
|
|
|
}
|
|
|
|
return filepath.Join(".pipeline", fileName), nil
|
|
|
|
}
|