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
            benhei Benjamin Heilbrunn added a comment -

            We already encountered multiple use cases where we needed to parse STDOUT in case a certain exit code happened. Would be great to have this feature.

            Show
            benhei Benjamin Heilbrunn added a comment - We already encountered multiple use cases where we needed to parse STDOUT in case a certain exit code happened. Would be great to have this feature.
            Hide
            rkumarrb Ramkumar Bangaru added a comment -

            In my case, I need it as my pipeline scripts need to branch out to different path based on the status and if the status is successful, based on the output of it. It makes a lot of sense to have both status and output returned by this function. 

            Show
            rkumarrb Ramkumar Bangaru added a comment - In my case, I need it as my pipeline scripts need to branch out to different path based on the status and if the status is successful, based on the output of it. It makes a lot of sense to have both status and output returned by this function. 
            Hide
            joanperez juan perez added a comment -

            We are using lots of python code called from the shared library, is a pain sh only returns an error code we would need a way to bubble the error message. Those solutions sounds good.

            Show
            joanperez juan perez added a comment - We are using lots of python code called from the shared library, is a pain sh only returns an error code we would need a way to bubble the error message. Those solutions sounds good.
            Hide
            conn JD Friedrikson added a comment - - edited

            Just sharing my workaround for others:

            pipeline {
              agent {
                docker {
                  image 'debian'
                }
              }
            
              stages {
                stage('script') {
                  steps {
                    script {
                      status = sh(
                        returnStatus: true,
            
                        script: '''#!/bin/bash
                          exec > >(tee output.log) 2>&1
                          echo 'one: stdout'
                          >&2 echo 'one: stderr'
                          exit 1
                        '''
                      )
            
                      output = readFile('output.log').trim()
                      echo output
            
                      if (status != 0) {
                        currentBuild.result = 'UNSTABLE'
                      }
                    }
                  }
                }
              }
            
              post {
                cleanup {
                  deleteDir()
                }
              }
            }
            
            [Pipeline] {
            [Pipeline] stage
            [Pipeline] { (script)
            [Pipeline] script
            [Pipeline] {
            [Pipeline] sh
            one: stdout
            one: stderr
            [Pipeline] readFile
            [Pipeline] echo
            one: stdout
            one: stderr
            [Pipeline] }
            [Pipeline] // script
            [Pipeline] }
            [Pipeline] // stage
            [Pipeline] stage
            [Pipeline] { (Declarative: Post Actions)
            [Pipeline] deleteDir (show)
            [Pipeline] }
            [Pipeline] // stage
            [Pipeline] }
            [Pipeline] // withDockerContainer
            [Pipeline] }
            [Pipeline] // node
            [Pipeline] End of Pipeline
            Finished: UNSTABLE
            
            Show
            conn JD Friedrikson added a comment - - edited Just sharing my workaround for others: pipeline { agent { docker { image 'debian' } } stages { stage( 'script' ) { steps { script { status = sh( returnStatus: true , script: '''#!/bin/bash exec > >(tee output.log) 2>&1 echo 'one: stdout' >&2 echo 'one: stderr' exit 1 ''' ) output = readFile( 'output.log' ).trim() echo output if (status != 0) { currentBuild.result = 'UNSTABLE' } } } } } post { cleanup { deleteDir() } } } [Pipeline] { [Pipeline] stage [Pipeline] { (script) [Pipeline] script [Pipeline] { [Pipeline] sh one: stdout one: stderr [Pipeline] readFile [Pipeline] echo one: stdout one: stderr [Pipeline] } [Pipeline] // script [Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (Declarative: Post Actions) [Pipeline] deleteDir (show) [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // withDockerContainer [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: UNSTABLE
            Hide
            gtirloni Giovanni Tirloni added a comment -

            By not making the Jenkins code "more complex" to support a common use case, Jenkins users everywhere need to make their code more complex. I'm certain the sum of "complexity" is much greater now than it would be if `sh` implemented this request. Talk about externalities.

            Show
            gtirloni Giovanni Tirloni added a comment - By not making the Jenkins code "more complex" to support a common use case, Jenkins users everywhere need to make their code more complex. I'm certain the sum of "complexity" is much greater now than it would be if `sh` implemented this request. Talk about externalities.

              People

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

                Dates

                • Created:
                  Updated: