diff --git a/common/support.go b/common/support.go index 3348b996e91f1e34283c67c87c1af19e1176d735..3daf8f58a7c20982412d4bb737910dcd3f2b2967 100644 --- a/common/support.go +++ b/common/support.go @@ -37,7 +37,16 @@ func GetRemoteLongRunningBuild() (JobResponse, error) { return getRemoteBuildResponse("sleep 3600") } -func getRemoteBuildResponse(commands string) (response JobResponse, err error) { +func GetMultilineBashBuild() (JobResponse, error) { + return getRemoteBuildResponse(`if true; then + bash \ + --login \ + -c 'echo Hello World' +fi +`) +} + +func getRemoteBuildResponse(commands ...string) (response JobResponse, err error) { response = JobResponse{ GitInfo: GitInfo{ RepoURL: repoRemoteURL, @@ -49,7 +58,7 @@ func getRemoteBuildResponse(commands string) (response JobResponse, err error) { Steps: Steps{ Step{ Name: StepNameScript, - Script: StepScript{commands}, + Script: commands, When: StepWhenAlways, AllowFailure: false, }, @@ -59,7 +68,7 @@ func getRemoteBuildResponse(commands string) (response JobResponse, err error) { return } -func getLocalBuildResponse(commands string) (response JobResponse, err error) { +func getLocalBuildResponse(commands ...string) (response JobResponse, err error) { localRepoURL, err := getLocalRepoURL() if err != nil { return @@ -76,7 +85,7 @@ func getLocalBuildResponse(commands string) (response JobResponse, err error) { Steps: Steps{ Step{ Name: StepNameScript, - Script: StepScript{commands}, + Script: commands, When: StepWhenAlways, AllowFailure: false, }, diff --git a/executors/shell/executor_shell_test.go b/executors/shell/executor_shell_test.go index dbdd4e52542b99f64dc0c6eac01547f7cb6e64e9..cb4eeaf2dfcbf58b65da2fe81ef07973d85f462b 100644 --- a/executors/shell/executor_shell_test.go +++ b/executors/shell/executor_shell_test.go @@ -442,3 +442,16 @@ func TestBuildWithDebugTrace(t *testing.T) { assert.Regexp(t, `[^$] echo Hello World`, out) }) } +func TestBuildMultilineCommand(t *testing.T) { + multilineBuild, err := common.GetMultilineBashBuild() + assert.NoError(t, err) + build, cleanup := newBuild(t, multilineBuild, "bash") + defer cleanup() + + // The default build shouldn't have debug tracing enabled + out, err := runBuildReturningOutput(t, build) + assert.NoError(t, err) + assert.NotContains(t, out, "bash") + assert.Contains(t, out, "Hello World") + assert.Contains(t, out, "collapsed multi-line command") +} diff --git a/helpers/gitlab_ci_yaml_parser/parser.go b/helpers/gitlab_ci_yaml_parser/parser.go index fd994610924f3273b1bf0bd11f3e79ba4f6a2b4d..a99704a5b96903bfd5f830acd428fcfb9cc2475b 100644 --- a/helpers/gitlab_ci_yaml_parser/parser.go +++ b/helpers/gitlab_ci_yaml_parser/parser.go @@ -67,15 +67,15 @@ func (c *GitLabCiYamlParser) prepareJobInfo(job *common.JobResponse) (err error) func (c *GitLabCiYamlParser) getCommands(commands interface{}) (common.StepScript, error) { if lines, ok := commands.([]interface{}); ok { - text := "" + var steps common.StepScript for _, line := range lines { if lineText, ok := line.(string); ok { - text += lineText + "\n" + steps = append(steps, lineText) } else { return common.StepScript{}, errors.New("unsupported script") } } - return common.StepScript(strings.Split(text, "\n")), nil + return steps, nil } else if text, ok := commands.(string); ok { return common.StepScript(strings.Split(text, "\n")), nil } else if commands != nil { @@ -116,9 +116,7 @@ func (c *GitLabCiYamlParser) prepareSteps(job *common.JobResponse) (err error) { if err != nil { return } - for _, scriptLine := range script { - scriptCommands = append(scriptCommands, scriptLine) - } + scriptCommands = append(scriptCommands, script...) afterScriptCommands, err = c.getCommands(c.jobConfig["after_script"]) if err != nil { diff --git a/shells/abstract.go b/shells/abstract.go index bacdd3292d31ab342af56c11b667478014b2b61d..d079540b1355c4c9d6ce41caaf09f5af656230e3 100644 --- a/shells/abstract.go +++ b/shells/abstract.go @@ -339,12 +339,17 @@ func (b *AbstractShell) writeDownloadArtifactsScript(w ShellWriter, info common. } // Write the given string of commands using the provided ShellWriter object. -func (b *AbstractShell) writeCommands(w ShellWriter, commands string) { - commands = strings.TrimSpace(commands) - for _, command := range strings.Split(commands, "\n") { +func (b *AbstractShell) writeCommands(w ShellWriter, commands ...string) { + for _, command := range commands { command = strings.TrimSpace(command) if command != "" { - w.Notice("$ %s", command) + lines := strings.SplitN(command, "\n", 2) + if len(lines) > 1 { + // TODO: this should be collapsable once we introduce that in GitLab + w.Notice("$ %s # collapsed multi-line command", lines[0]) + } else { + w.Notice("$ %s", lines[0]) + } } else { w.EmptyLine() } @@ -373,8 +378,7 @@ func (b *AbstractShell) writeUserScript(w ShellWriter, info common.ShellScriptIn b.writeCommands(w, info.PreBuildScript) } - commands := strings.Join(scriptStep.Script, "\n") - b.writeCommands(w, commands) + b.writeCommands(w, scriptStep.Script...) if info.PostBuildScript != "" { b.writeCommands(w, info.PostBuildScript) @@ -503,18 +507,7 @@ func (b *AbstractShell) writeAfterScript(w ShellWriter, info common.ShellScriptI b.writeCdBuildDir(w, info) w.Notice("Running after script...") - - for _, command := range afterScriptStep.Script { - command = strings.TrimSpace(command) - if command != "" { - w.Notice("$ %s", command) - } else { - w.EmptyLine() - } - w.Line(command) - w.CheckForErrors() - } - + b.writeCommands(w, afterScriptStep.Script...) return nil }