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

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

    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
            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.
            Hide
            monger39 David Riemens added a comment -

            I like the solution by Suraj Sharma for smaller outputs. However I have a few calls (using 'bat') that run quite long. I am looking to:

            • capture the exitcode to see if the step passed/failed
            • capture (grep) for a few specific lines in the output from stdout or stderr that contain more info.
              I want to store that info for reporting detailed results at the end
            • see the progress of the output 'live', rather than a single dump at the end.
              Yeah, write to file with 'tee' works, but there should be better solutions ... 

            So although I'd vote for having the 'object' returned as described by Fernando Nasser it would be great if I would also be able to optionally pass a method that does the magic I need. In my case grep for some pattern in stdout, and store it such that it is available after the bat/sh step.

            I've been looking at using a 'listener' as described in eg

               https://stackoverflow.com/questions/53172023/get-console-logger-or-tasklistener-from-pipeline-script-method

            but have not found a (working) way yet to apply this in a scripted pipeline. Anyone

            Show
            monger39 David Riemens added a comment - I like the solution by Suraj Sharma for smaller outputs. However I have a few calls (using 'bat') that run quite long. I am looking to: capture the exitcode to see if the step passed/failed capture (grep) for a few specific lines in the output from stdout or stderr that contain more info. I want to store that info for reporting detailed results at the end see the progress of the output 'live', rather than a single dump at the end. Yeah, write to file with 'tee' works, but there should be better solutions ...  So although I'd vote for having the 'object' returned as described by Fernando Nasser it would be great if I would also be able to optionally pass a method that does the magic I need. In my case grep for some pattern in stdout, and store it such that it is available after the bat/sh step. I've been looking at using a 'listener' as described in eg     https://stackoverflow.com/questions/53172023/get-console-logger-or-tasklistener-from-pipeline-script-method but have not found a (working) way yet to apply this in a scripted pipeline. Anyone

              People

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

                Dates

                • Created:
                  Updated: