Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-44930

Allow sh to return exit status, stdout and stderr all at once

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      Like many of the commenters on -JENKINS-26133- I'd like to be able to capture the exit status and text written to standard out at the same time.

      My current use case is calling git merge --no-edit $branches and if there was an error sending a slack notification with the output. 

      The current workaround is:

      def status = sh(returnStatus: true, script: "git merge --no-edit $branches > merge_output.txt")
      if (status != 0) {
        currentBuild.result = 'FAILED'
        def output = readFile('merge_output.txt').trim()
        slackSend channel: SLACK_CHANNEL, message: "<${env.JOB_URL}|${env.JOB_NAME}> ran into an error merging the PR branches into the ${TARGET_BRANCH} branch:\n```\n${output}\n```\n<${env.BUILD_URL}/console|See the full output>", color: 'warning', tokenCredentialId: 'slack-token'
        error 'Merge conflict'
      }
      sh 'rm merge_output.txt'

      Which works but isn't a great developer experience... It would be great if I could request an object that contained: status, stdout, and stderr.

        Attachments

          Issue Links

            Activity

            Hide
            fnasser Fernando Nasser added a comment -

            Although I am one of the supporters for the implementation of a solution to this JIRA I have to object to a solution like:

            " I believe command "sh" should always return an object with all relevant output (stdout, stderr, exit_code) "

            Output of sysout and syserr may be too extensive, have all sort of characters, etc.  We had a system that included the output as one of the fields of a JSON output and that was always causing problems, requiring retrying, etc.

            The workaround for this JIRA that we are using for quite some time and it is working very well is to, if output is requested, write it to a file in the WORSPACE.  We do it by piping the output (sysout and/or syserr) but that should be much clear if done by the command itself.

             

            Show
            fnasser Fernando Nasser added a comment - Although I am one of the supporters for the implementation of a solution to this JIRA I have to object to a solution like: " I believe command "sh" should always return an object with all relevant output (stdout, stderr, exit_code) " Output of sysout and syserr may be too extensive, have all sort of characters, etc.  We had a system that included the output as one of the fields of a JSON output and that was always causing problems, requiring retrying, etc. The workaround for this JIRA that we are using for quite some time and it is working very well is to, if output is requested, write it to a file in the WORSPACE.  We do it by piping the output (sysout and/or syserr) but that should be much clear if done by the command itself.  
            Hide
            nolange79 Norbert Lange added a comment -

            Fernando Nasser: I would like and prefer a dump into a file into workspace, while also having normal output.

            I am not sure what you mean by "command", you you mean the pipeline command ("sh"), or the native script?
            The native script is cumbersome, there might even be different ways with different shells,
            if you meant the pipeline command then I am all for it.

            but some other idea would be to use a context wrappers like

            output(stdout: "build.log",  stderr: "err.log") {
               sh 'cmake --build .'
            }
            
            Show
            nolange79 Norbert Lange added a comment - Fernando Nasser : I would like and prefer a dump into a file into workspace, while also having normal output. I am not sure what you mean by "command", you you mean the pipeline command ("sh"), or the native script? The native script is cumbersome, there might even be different ways with different shells, if you meant the pipeline command then I am all for it. but some other idea would be to use a context wrappers like output(stdout: "build.log", stderr: "err.log") { sh 'cmake --build .' }
            Hide
            surajs21 Suraj Sharma added a comment - - edited

            Maybe this small function can help take care of exit status and stdout.

            def runCommand(script) {    
                echo "[runCommand:script] ${script}"
            
                def stdoutFile = "rc.${BUILD_NUMBER}.out"    
                script = script + " > " + stdoutFile
            
                def res = [:]    
                res["exitCode"] = sh(returnStatus: true, script: script)    
                res["stdout"] = sh(returnStdout: true, script: "cat " + stdoutFile)
            
                sh(returnStatus: true, script: "rm -f " + stdoutFile)
            
                echo "[runCommand:response] ${res}"    
                return res
            }
            

            Example Usage

                def response = runCommand("date")
                echo response["exitCode"]
                echo response["stdout"]
            
            Show
            surajs21 Suraj Sharma added a comment - - edited Maybe this small function can help take care of exit status and stdout. def runCommand(script) { echo "[runCommand:script] ${script}" def stdoutFile = "rc.${BUILD_NUMBER}.out" script = script + " > " + stdoutFile def res = [:] res[ "exitCode" ] = sh(returnStatus: true , script: script) res[ "stdout" ] = sh(returnStdout: true , script: "cat " + stdoutFile) sh(returnStatus: true , script: "rm -f " + stdoutFile) echo "[runCommand:response] ${res}" return res } Example Usage def response = runCommand( "date" ) echo response[ "exitCode" ] echo response[ "stdout" ]
            Hide
            fnasser Fernando Nasser added a comment -

            Norbert Lange   The "command" was in a quote, but yes, we were talking about the 'sh' step.

            In fact we use "tee" after the '|' so we are also showing the command output in the log.  

            I agree that the output should also go to the log.

            Show
            fnasser Fernando Nasser added a comment - Norbert Lange   The "command" was in a quote, but yes, we were talking about the 'sh' step. In fact we use "tee" after the '|' so we are also showing the command output in the log.   I agree that the output should also go to the log.
            Hide
            akostadinov akostadinov added a comment -

            Suraj Sharma, and if you have a multiline string that function works in a surprising way. It needs to be done on the lower level by the plugin to be reliable.
            I actually wonder if we can have a console wrapper that will capture whatever output produced inside. Like AnsiColor Plugin. It will not be able to differentiate stdin from stderr though.

            Show
            akostadinov akostadinov added a comment - Suraj Sharma , and if you have a multiline string that function works in a surprising way. It needs to be done on the lower level by the plugin to be reliable. I actually wonder if we can have a console wrapper that will capture whatever output produced inside. Like AnsiColor Plugin . It will not be able to differentiate stdin from stderr though.

              People

              • Assignee:
                Unassigned
                Reporter:
                drewish andrew morton
              • Votes:
                86 Vote for this issue
                Watchers:
                76 Start watching this issue

                Dates

                • Created:
                  Updated: