github.com/kubeshop/testkube@v1.17.23/cmd/tcl/testworkflow-init/run/run.go (about) 1 // Copyright 2024 Testkube. 2 // 3 // Licensed as a Testkube Pro file under the Testkube Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt 8 9 package run 10 11 import ( 12 "fmt" 13 "os" 14 "os/exec" 15 16 "github.com/kubeshop/testkube/cmd/tcl/testworkflow-init/data" 17 "github.com/kubeshop/testkube/cmd/tcl/testworkflow-init/utils" 18 ) 19 20 const ( 21 defaultBinPath = "/.tktw/bin" 22 ) 23 24 func getProcessStatus(err error) (bool, uint8) { 25 if err == nil { 26 return true, 0 27 } 28 if e, ok := err.(*exec.ExitError); ok { 29 if e.ProcessState != nil { 30 return false, uint8(e.ProcessState.ExitCode()) 31 } 32 return false, 1 33 } 34 fmt.Println(err.Error()) 35 return false, 1 36 } 37 38 // TODO: Obfuscate Stdout/Stderr streams 39 func createCommand(cmd string, args ...string) (c *exec.Cmd) { 40 c = exec.Command(cmd, args...) 41 out := utils.NewOutputProcessor(data.Step.Ref, os.Stdout) 42 c.Stdout = out 43 c.Stderr = os.Stderr 44 c.Stdin = os.Stdin 45 return 46 } 47 48 func execute(cmd string, args ...string) { 49 data.Step.Cmd = createCommand(cmd, args...) 50 success, exitCode := getProcessStatus(data.Step.Cmd.Run()) 51 data.Step.ExitCode = exitCode 52 53 actualSuccess := success 54 if data.Config.Negative { 55 actualSuccess = !success 56 } 57 58 if actualSuccess { 59 data.Step.Status = data.StepStatusPassed 60 } else { 61 data.Step.Status = data.StepStatusFailed 62 } 63 64 if data.Config.Negative { 65 fmt.Printf("Expected to fail: finished with exit code %d.\n", exitCode) 66 } else if data.Config.Debug { 67 fmt.Printf("Exit code: %d.\n", exitCode) 68 } 69 } 70 71 func Run(cmd string, args []string) { 72 // Ensure the built-in binaries are available 73 if os.Getenv("PATH") == "" { 74 _ = os.Setenv("PATH", defaultBinPath) 75 } else { 76 _ = os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), defaultBinPath)) 77 } 78 79 // Instantiate the command and run 80 execute(cmd, args...) 81 82 // Retry if it's expected 83 // TODO: Support nested retries 84 step := data.State.GetStep(data.Step.Ref) 85 for step.Iteration <= uint64(data.Config.RetryCount) { 86 expr, err := data.Expression(data.Config.RetryUntil, data.LocalMachine) 87 if err != nil { 88 fmt.Printf("Failed to execute retry condition: %s: %s\n", data.Config.RetryUntil, err.Error()) 89 data.Finish() 90 } 91 v, _ := expr.BoolValue() 92 if v { 93 break 94 } 95 step.Next() 96 fmt.Printf("\nExit code: %d • Retrying: attempt #%d (of %d):\n", data.Step.ExitCode, step.Iteration-1, data.Config.RetryCount) 97 execute(cmd, args...) 98 } 99 100 // Finish 101 data.Finish() 102 }