You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-07-17 01:42:43 +02:00
Run npm scripts in virtual frame buffer and extend command.go to run executable asynchronously (#1669)
Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com> Co-authored-by: Florian Wilhelm <florian.wilhelm02@sap.com>
This commit is contained in:
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bmatcuk/doublestar"
|
"github.com/bmatcuk/doublestar"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
@ -35,6 +36,13 @@ type pullRequestService interface {
|
|||||||
ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error)
|
ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fortifyExecRunner interface {
|
||||||
|
Stdout(out io.Writer)
|
||||||
|
Stderr(err io.Writer)
|
||||||
|
SetDir(d string)
|
||||||
|
RunExecutable(e string, p ...string) error
|
||||||
|
}
|
||||||
|
|
||||||
const checkString = "<---CHECK FORTIFY---"
|
const checkString = "<---CHECK FORTIFY---"
|
||||||
const classpathFileName = "fortify-execute-scan-cp.txt"
|
const classpathFileName = "fortify-execute-scan-cp.txt"
|
||||||
|
|
||||||
@ -51,7 +59,7 @@ func fortifyExecuteScan(config fortifyExecuteScanOptions, telemetryData *telemet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, command execRunner, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux, auditStatus map[string]string) error {
|
func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, command fortifyExecRunner, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux, auditStatus map[string]string) error {
|
||||||
log.Entry().Debugf("Running Fortify scan against SSC at %v", config.ServerURL)
|
log.Entry().Debugf("Running Fortify scan against SSC at %v", config.ServerURL)
|
||||||
artifact, err := versioning.GetArtifact(config.BuildTool, config.BuildDescriptorFile, &versioning.Options{}, command)
|
artifact, err := versioning.GetArtifact(config.BuildTool, config.BuildDescriptorFile, &versioning.Options{}, command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -447,7 +455,7 @@ func calculateTimeDifferenceToLastUpload(uploadDate models.Iso8601MilliDateTime,
|
|||||||
return absoluteSeconds
|
return absoluteSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeTemplatedCommand(command execRunner, cmdTemplate []string, context map[string]string) {
|
func executeTemplatedCommand(command fortifyExecRunner, cmdTemplate []string, context map[string]string) {
|
||||||
for index, cmdTemplatePart := range cmdTemplate {
|
for index, cmdTemplatePart := range cmdTemplate {
|
||||||
result, err := piperutils.ExecuteTemplate(cmdTemplatePart, context)
|
result, err := piperutils.ExecuteTemplate(cmdTemplatePart, context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -461,7 +469,7 @@ func executeTemplatedCommand(command execRunner, cmdTemplate []string, context m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoresolvePipClasspath(executable string, parameters []string, file string, command execRunner) string {
|
func autoresolvePipClasspath(executable string, parameters []string, file string, command fortifyExecRunner) string {
|
||||||
// redirect stdout and create cp file from command output
|
// redirect stdout and create cp file from command output
|
||||||
outfile, err := os.Create(file)
|
outfile, err := os.Create(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -477,7 +485,7 @@ func autoresolvePipClasspath(executable string, parameters []string, file string
|
|||||||
return readClasspathFile(file)
|
return readClasspathFile(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoresolveMavenClasspath(config fortifyExecuteScanOptions, file string, command execRunner) string {
|
func autoresolveMavenClasspath(config fortifyExecuteScanOptions, file string, command fortifyExecRunner) string {
|
||||||
if filepath.IsAbs(file) {
|
if filepath.IsAbs(file) {
|
||||||
log.Entry().Warnf("Passing an absolute path for -Dmdep.outputFile results in the classpath only for the last module in multi-module maven projects.")
|
log.Entry().Warnf("Passing an absolute path for -Dmdep.outputFile results in the classpath only for the last module in multi-module maven projects.")
|
||||||
}
|
}
|
||||||
@ -552,7 +560,7 @@ func removeDuplicates(contents, separator string) string {
|
|||||||
return contents
|
return contents
|
||||||
}
|
}
|
||||||
|
|
||||||
func triggerFortifyScan(config fortifyExecuteScanOptions, command execRunner, buildID, buildLabel, buildProject string) {
|
func triggerFortifyScan(config fortifyExecuteScanOptions, command fortifyExecRunner, buildID, buildLabel, buildProject string) {
|
||||||
var err error = nil
|
var err error = nil
|
||||||
// Do special Python related prep
|
// Do special Python related prep
|
||||||
pipVersion := "pip3"
|
pipVersion := "pip3"
|
||||||
@ -639,7 +647,7 @@ func populateMavenTranslate(config *fortifyExecuteScanOptions, classpath string)
|
|||||||
return string(translateJSON), err
|
return string(translateJSON), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateProject(config *fortifyExecuteScanOptions, command execRunner, buildID, classpath string) {
|
func translateProject(config *fortifyExecuteScanOptions, command fortifyExecRunner, buildID, classpath string) {
|
||||||
var translateList []map[string]string
|
var translateList []map[string]string
|
||||||
json.Unmarshal([]byte(config.Translate), &translateList)
|
json.Unmarshal([]byte(config.Translate), &translateList)
|
||||||
log.Entry().Debugf("Translating with options: %v", translateList)
|
log.Entry().Debugf("Translating with options: %v", translateList)
|
||||||
@ -651,7 +659,7 @@ func translateProject(config *fortifyExecuteScanOptions, command execRunner, bui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSingleTranslate(config *fortifyExecuteScanOptions, command execRunner, buildID string, t map[string]string) {
|
func handleSingleTranslate(config *fortifyExecuteScanOptions, command fortifyExecRunner, buildID string, t map[string]string) {
|
||||||
if t != nil {
|
if t != nil {
|
||||||
log.Entry().Debugf("Handling translate config %v", t)
|
log.Entry().Debugf("Handling translate config %v", t)
|
||||||
translateOptions := []string{
|
translateOptions := []string{
|
||||||
@ -672,7 +680,7 @@ func handleSingleTranslate(config *fortifyExecuteScanOptions, command execRunner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanProject(config *fortifyExecuteScanOptions, command execRunner, buildID, buildLabel, buildProject string) {
|
func scanProject(config *fortifyExecuteScanOptions, command fortifyExecRunner, buildID, buildLabel, buildProject string) {
|
||||||
var scanOptions = []string{
|
var scanOptions = []string{
|
||||||
"-verbose",
|
"-verbose",
|
||||||
"-64",
|
"-64",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/SAP/jenkins-library/pkg/command"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ type runner interface {
|
|||||||
type execRunner interface {
|
type execRunner interface {
|
||||||
runner
|
runner
|
||||||
RunExecutable(e string, p ...string) error
|
RunExecutable(e string, p ...string) error
|
||||||
|
RunExecutableInBackground(executable string, params ...string) (command.Execution, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type shellRunner interface {
|
type shellRunner interface {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/SAP/jenkins-library/pkg/command"
|
"github.com/SAP/jenkins-library/pkg/command"
|
||||||
"github.com/SAP/jenkins-library/pkg/log"
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
"github.com/SAP/jenkins-library/pkg/npm"
|
"github.com/SAP/jenkins-library/pkg/npm"
|
||||||
@ -71,6 +72,15 @@ func runNpmExecuteScripts(utils npmExecuteScriptsUtilsInterface, options *npmExe
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.VirtualFrameBuffer {
|
||||||
|
cmd, err := execRunner.RunExecutableInBackground("Xvfb", "-ac", ":99", "-screen", "0", "1280x1024x16")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start virtual frame buffer%w", err)
|
||||||
|
}
|
||||||
|
defer cmd.Kill()
|
||||||
|
execRunner.SetEnv([]string{"DISPLAY=:99"})
|
||||||
|
}
|
||||||
|
|
||||||
for _, file := range packageJSONFiles {
|
for _, file := range packageJSONFiles {
|
||||||
dir := path.Dir(file)
|
dir := path.Dir(file)
|
||||||
err = utils.chdir(dir)
|
err = utils.chdir(dir)
|
||||||
|
@ -18,6 +18,7 @@ type npmExecuteScriptsOptions struct {
|
|||||||
RunScripts []string `json:"runScripts,omitempty"`
|
RunScripts []string `json:"runScripts,omitempty"`
|
||||||
DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"`
|
DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"`
|
||||||
SapNpmRegistry string `json:"sapNpmRegistry,omitempty"`
|
SapNpmRegistry string `json:"sapNpmRegistry,omitempty"`
|
||||||
|
VirtualFrameBuffer bool `json:"virtualFrameBuffer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NpmExecuteScriptsCommand Execute npm run scripts on all npm packages in a project
|
// NpmExecuteScriptsCommand Execute npm run scripts on all npm packages in a project
|
||||||
@ -78,6 +79,7 @@ func addNpmExecuteScriptsFlags(cmd *cobra.Command, stepConfig *npmExecuteScripts
|
|||||||
cmd.Flags().StringSliceVar(&stepConfig.RunScripts, "runScripts", []string{}, "List of additional run scripts to execute from package.json.")
|
cmd.Flags().StringSliceVar(&stepConfig.RunScripts, "runScripts", []string{}, "List of additional run scripts to execute from package.json.")
|
||||||
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "URL of the npm registry to use. Defaults to https://registry.npmjs.org/")
|
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "URL of the npm registry to use. Defaults to https://registry.npmjs.org/")
|
||||||
cmd.Flags().StringVar(&stepConfig.SapNpmRegistry, "sapNpmRegistry", `https://npm.sap.com`, "The default npm registry URL to be used as the remote mirror for the SAP npm packages.")
|
cmd.Flags().StringVar(&stepConfig.SapNpmRegistry, "sapNpmRegistry", `https://npm.sap.com`, "The default npm registry URL to be used as the remote mirror for the SAP npm packages.")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.VirtualFrameBuffer, "virtualFrameBuffer", false, "(Linux only) Start a virtual frame buffer in the background. This allows you to run a web browser without the need for an X server. Note that xvfb needs to be installed in the execution environment.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +125,14 @@ func npmExecuteScriptsMetadata() config.StepData {
|
|||||||
Mandatory: false,
|
Mandatory: false,
|
||||||
Aliases: []config.Alias{},
|
Aliases: []config.Alias{},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "virtualFrameBuffer",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -129,6 +129,29 @@ func TestNpmExecuteScripts(t *testing.T) {
|
|||||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
|
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
|
||||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[4])
|
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[4])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Call run-scripts with virtual frame buffer", func(t *testing.T) {
|
||||||
|
utils := newNpmExecuteScriptsMockUtilsBundle()
|
||||||
|
utils.files["package.json"] = []byte("{\"scripts\": { \"foo\": \"\" } }")
|
||||||
|
options := npmExecuteScriptsOptions{}
|
||||||
|
options.Install = false
|
||||||
|
options.RunScripts = []string{"foo"}
|
||||||
|
options.VirtualFrameBuffer = true
|
||||||
|
|
||||||
|
err := runNpmExecuteScripts(&utils, &options)
|
||||||
|
|
||||||
|
assert.Contains(t, utils.execRunner.Env, "DISPLAY=:99")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, utils.execRunner.Calls, 4) {
|
||||||
|
xvfbCall := utils.execRunner.Calls[0]
|
||||||
|
assert.Equal(t, "Xvfb", xvfbCall.Exec)
|
||||||
|
assert.Equal(t, []string{"-ac", ":99", "-screen", "0", "1280x1024x16"}, xvfbCall.Params)
|
||||||
|
assert.True(t, xvfbCall.Async)
|
||||||
|
assert.True(t, xvfbCall.Execution.Killed)
|
||||||
|
|
||||||
|
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNpmExecuteScriptsMockUtilsBundle() npmExecuteScriptsMockUtilsBundle {
|
func newNpmExecuteScriptsMockUtilsBundle() npmExecuteScriptsMockUtilsBundle {
|
||||||
|
@ -4,13 +4,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/SAP/jenkins-library/pkg/log"
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command defines the information required for executing a call to any executable
|
// Command defines the information required for executing a call to any executable
|
||||||
@ -92,6 +90,32 @@ func (c *Command) RunExecutable(executable string, params ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunExecutableInBackground runs the specified executable with parameters in the background non blocking
|
||||||
|
// !! While the cmd.Env is applied during command execution, it is NOT involved when the actual executable is resolved.
|
||||||
|
// Thus the executable needs to be on the PATH of the current process and it is not sufficient to alter the PATH on cmd.Env.
|
||||||
|
func (c *Command) RunExecutableInBackground(executable string, params ...string) (Execution, error) {
|
||||||
|
|
||||||
|
_out, _err := prepareOut(c.stdout, c.stderr)
|
||||||
|
|
||||||
|
cmd := ExecCommand(executable, params...)
|
||||||
|
|
||||||
|
if len(c.dir) > 0 {
|
||||||
|
cmd.Dir = c.dir
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Infof("running command: %v %v", executable, strings.Join(params, (" ")))
|
||||||
|
|
||||||
|
appendEnvironment(cmd, c.env)
|
||||||
|
|
||||||
|
execution, err := startCmd(cmd, _out, _err)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "starting command '%v' failed", executable)
|
||||||
|
}
|
||||||
|
|
||||||
|
return execution, nil
|
||||||
|
}
|
||||||
|
|
||||||
func appendEnvironment(cmd *exec.Cmd, env []string) {
|
func appendEnvironment(cmd *exec.Cmd, env []string) {
|
||||||
|
|
||||||
if len(env) > 0 {
|
if len(env) > 0 {
|
||||||
@ -119,46 +143,52 @@ func appendEnvironment(cmd *exec.Cmd, env []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCmd(cmd *exec.Cmd, _out, _err io.Writer) error {
|
func startCmd(cmd *exec.Cmd, _out, _err io.Writer) (*execution, error) {
|
||||||
|
|
||||||
stdout, stderr, err := cmdPipes(cmd)
|
stdout, stderr, err := cmdPipes(cmd)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "getting commmand pipes failed")
|
return nil, errors.Wrap(err, "getting command pipes failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "starting command failed")
|
return nil, errors.Wrap(err, "starting command failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
execution := execution{cmd: cmd}
|
||||||
wg.Add(2)
|
execution.wg.Add(2)
|
||||||
|
|
||||||
var errStdout, errStderr error
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, errStdout = io.Copy(_out, stdout)
|
_, execution.errCopyStdout = io.Copy(_out, stdout)
|
||||||
wg.Done()
|
execution.wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, errStderr = io.Copy(_err, stderr)
|
_, execution.errCopyStderr = io.Copy(_err, stderr)
|
||||||
wg.Done()
|
execution.wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
return &execution, nil
|
||||||
|
}
|
||||||
|
|
||||||
err = cmd.Wait()
|
func runCmd(cmd *exec.Cmd, _out, _err io.Writer) error {
|
||||||
|
|
||||||
|
execution, err := startCmd(cmd, _out, _err)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = execution.Wait()
|
||||||
|
|
||||||
|
if execution.errCopyStdout != nil || execution.errCopyStderr != nil {
|
||||||
|
return fmt.Errorf("failed to capture stdout/stderr: '%v'/'%v'", execution.errCopyStdout, execution.errCopyStderr)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "cmd.Run() failed")
|
return errors.Wrap(err, "cmd.Run() failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if errStdout != nil || errStderr != nil {
|
|
||||||
return fmt.Errorf("failed to capture stdout/stderr: '%v'/'%v'", errStdout, errStderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
pkg/command/execution.go
Normal file
29
pkg/command/execution.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
//errCopyStdout and errCopyStderr are filled after the command execution after Wait() terminates
|
||||||
|
type execution struct {
|
||||||
|
cmd *exec.Cmd
|
||||||
|
wg sync.WaitGroup
|
||||||
|
errCopyStdout error
|
||||||
|
errCopyStderr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (execution *execution) Kill() error {
|
||||||
|
return execution.cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (execution *execution) Wait() error {
|
||||||
|
execution.wg.Wait()
|
||||||
|
return execution.cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execution references a background process which is started by RunExecutableInBackground
|
||||||
|
type Execution interface {
|
||||||
|
Kill() error
|
||||||
|
Wait() error
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
package mock
|
package mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/SAP/jenkins-library/pkg/command"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -20,8 +21,14 @@ type ExecMockRunner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExecCall struct {
|
type ExecCall struct {
|
||||||
Exec string
|
Execution *Execution
|
||||||
Params []string
|
Async bool
|
||||||
|
Exec string
|
||||||
|
Params []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Execution struct {
|
||||||
|
Killed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShellMockRunner struct {
|
type ShellMockRunner struct {
|
||||||
@ -53,6 +60,21 @@ func (m *ExecMockRunner) RunExecutable(e string, p ...string) error {
|
|||||||
return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
|
return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ExecMockRunner) RunExecutableInBackground(e string, p ...string) (command.Execution, error) {
|
||||||
|
|
||||||
|
execution := Execution{}
|
||||||
|
exec := ExecCall{Exec: e, Params: p, Async: true, Execution: &execution}
|
||||||
|
m.Calls = append(m.Calls, exec)
|
||||||
|
|
||||||
|
c := strings.Join(append([]string{e}, p...), " ")
|
||||||
|
|
||||||
|
err := handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &execution, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *ExecMockRunner) Stdout(out io.Writer) {
|
func (m *ExecMockRunner) Stdout(out io.Writer) {
|
||||||
m.stdout = out
|
m.stdout = out
|
||||||
}
|
}
|
||||||
@ -81,6 +103,15 @@ func (m *ShellMockRunner) RunShell(s string, c string) error {
|
|||||||
return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
|
return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Execution) Kill() error {
|
||||||
|
e.Killed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Execution) Wait() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleCall(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error {
|
func handleCall(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error {
|
||||||
|
|
||||||
if stdoutReturn != nil {
|
if stdoutReturn != nil {
|
||||||
|
@ -38,6 +38,13 @@ spec:
|
|||||||
- STAGES
|
- STAGES
|
||||||
- STEPS
|
- STEPS
|
||||||
default: https://npm.sap.com
|
default: https://npm.sap.com
|
||||||
|
- name: virtualFrameBuffer
|
||||||
|
type: bool
|
||||||
|
description: (Linux only) Start a virtual frame buffer in the background. This allows you to run a web browser without the need for an X server. Note that xvfb needs to be installed in the execution environment.
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
containers:
|
containers:
|
||||||
- name: node
|
- name: node
|
||||||
image: node:12-buster-slim
|
image: node:12-buster-slim
|
||||||
|
Reference in New Issue
Block a user