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

Pipeline-Maven-Plugin - UNSTABLE build with downstream list of parent job

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • pipeline-maven-plugin
    • None
    • Jenkins ver. 2.164.1
      pipeline-maven-plugin: 3.6.9

      Hi,
       
      Here is my context.
      I have a pipeline with main steps:

      • mvn clean deploy
      • mvn test
      • sonar quality gate

      I choose to set currentBuild.result = 'UNSTABLE' if last step (quality gate from Sonar) is not OK.
      I want my dependencies to build automatically downstream projects when SNAPSHOT.
      Everything works well when quality gate is OK (means the job is SUCCESS):
      If my newly SUCCESSed project A contains SNAPSHOTed dependencies B, I can see on "Downstream Jobs" of this dependency B the newly build project.
      So, when I build this dependency B, on finished, job from project A is launched.
       
      BUT
       
      If my job from project A is UNSTABLE, it won't be referenced as a downstream Job from dependency B (so building B will no trigger A). I have to build at least once in SUCCESS (by ex. by bypassing SONAR GATE) to see it in "Downstream Jobs" of my parent project.
       
      I'd like my parent "Downstream jobs" list updated for a project that is SUCCESS or UNSTABLE.
       
      Thanks
       

      def call(body) {
        // evaluate the body block, and collect configuration into the object
        def pipelineParams = [:]
        body.resolveStrategy = Closure.DELEGATE_FIRST
        body.delegate = pipelineParams
        body()
      
        // Get Artifactory server instance, defined in the Artifactory Plugin administration page.
        def artifactory = Artifactory.server "ARTIFACTORY"
      
        def scmUrl
      
        def trimOrigin = {
          it.startsWith('origin/') ? it.trim() - 'origin/' : it.trim()
        }
      
        node('maven') {
          try {
            stage('Clone sources') {
              // Keep only last 3 builds + disable concurrent builds
              properties([
                  buildDiscarder(
                      logRotator(
                          artifactDaysToKeepStr: '',
                          artifactNumToKeepStr: '',
                          daysToKeepStr: '',
                          numToKeepStr: '3')
                  ),
                  disableConcurrentBuilds()
              ])
      
              testFailure = false
              buildFailure = false
      
              // MULTIBRANCH: Branch is part of the context: so use BRANCH_NAME
              branchTobuild = env.BRANCH_NAME
              echo "branchTobuild=${branchTobuild}"
      
              // Scm url
              scmUrl = scm.getUserRemoteConfigs()[0].getUrl()
      
              // Clean
              step([$class: 'WsCleanup', cleanWhenFailure: false])
      
              // Get code from a Gitlab repository
              git branch: trimOrigin(branchTobuild), credentialsId: 'jenkins', url: scmUrl
      
              shortCommit = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%H'").trim()
      
               // Get deployPath
              deployPath = pipelineParams.deployPath ?: ""
              echo "deployPath:${deployPath}"
      
              // Is this component deployable (if not, no need to display deploy buttons in Slack)
              deployable = pipelineParams.isDeployable ?: true
              echo "deployable:${deployable}"
            }
      
            stage('Maven build') {
              withMaven(maven: 'Maven 3.6.0', options: [junitPublisher(disabled: true)]) {
                try {
                  sh 'mvn -U -T 2 clean deploy -DskipTests -Dmaven.javadoc.skip=true'
                } catch (e) {
                  buildFailure = true
                  throw e
                }
              }
            }
      
            stage('Running tests') {
              try {
                sh 'mvn -T 2 --errors test -DfailIfNoTests=false -Dsurefire.useSystemClassLoader=false'
              } catch (e) {
                // if any exception occurs, mark the build as failed
                testFailure = true
                throw e
              } finally {
                junit(testResults: '**/surefire-reports/*xml', allowEmptyResults: true)
              }
            }
      
            stage('SonarQube analysis') {
              withSonarQubeEnv('Sonar') {
                sh "mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar \
                   -Dsonar.sources='.' \
                   -Dsonar.inclusions='pom.xml,src/main/web/**,src/main/java/**' \
                   -Dsonar.exclusions='src/main/web/node_modules/**' \
                   -Dsonar.upsource.url='https://upsource.ehtrace.com' \
                   -Dsonar.upsource.project=${pomArtifactId} \
                   -Dsonar.upsource.revision=${shortCommit} \
                   -Dsonar.upsource.token='***********'"
              }
            }
      
            stage("Notify slack Quality Gate") {
              timeout(time: 1, unit: 'HOURS') {
                // Just in case something goes wrong, pipeline will be killed after a timeout
                def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
                if (qg.status != 'OK') {
                  currentBuild.result = 'UNSTABLE'
                  echo "Pipeline aborted due to quality gate failure: ${qg.status}"
                  notifySlackStatus('SONAR_QUALITY_GATE_FAILURE')
                } else {
                  currentBuild.result = 'SUCCESS'
                  notifySlackStatus('SUCCESS')
                }
              }
            }
          } catch (Exception e) {
            // if any exception occurs, mark the build as failed
            echo e.message
      
            currentBuild.result = 'FAILURE'
            if (buildFailure == true) {
              notifySlackStatus('BUILD_FAILURE')
            } else if (testFailure == true) {
              notifySlackStatus('TEST_FAILURE')
            } else {
              notifySlackStatus('FAILURE')
            }
            throw e // rethrow so the build is considered failed
          }
        }
      }
      

          [JENKINS-57108] Pipeline-Maven-Plugin - UNSTABLE build with downstream list of parent job

          benjamin tocquec created issue -
          benjamin tocquec made changes -
          Attachment New: pipeline.groovy [ 46960 ]
          Cyrille Le Clerc made changes -
          Description Original: Hi,
           
          Here is my context.
          I have a pipeline with main steps:
           * mvn clean deploy
           * mvn test
           * sonar quality gate

          I choose to set currentBuild.result = 'UNSTABLE' if last step (quality gate from Sonar) is not OK.
          I want my dependencies to build automatically downstream projects when SNAPSHOT.
          Everything works well when quality gate is OK (means the job is SUCCESS):
          If my newly SUCCESSed project A contains SNAPSHOTed dependencies B, I can see on "Downstream Jobs" of this dependency B the newly build project.
          So, when I build this dependency B, on finished, job from project A is launched.
           
          BUT
           
          If my job from project A is UNSTABLE, it won't be referenced as a downstream Job from dependency B (so building B will no trigger A). I have to build at least once in SUCCESS (by ex. by bypassing SONAR GATE) to see it in "Downstream Jobs" of my parent project.
           
          I'd like my parent "Downstream jobs" list updated for a project that is SUCCESS or UNSTABLE.
           
          Thanks
           
          New: Hi,
           
          Here is my context.
          I have a pipeline with main steps:
           * mvn clean deploy
           * mvn test
           * sonar quality gate

          I choose to set currentBuild.result = 'UNSTABLE' if last step (quality gate from Sonar) is not OK.
          I want my dependencies to build automatically downstream projects when SNAPSHOT.
          Everything works well when quality gate is OK (means the job is SUCCESS):
          If my newly SUCCESSed project A contains SNAPSHOTed dependencies B, I can see on "Downstream Jobs" of this dependency B the newly build project.
          So, when I build this dependency B, on finished, job from project A is launched.
           
          BUT
           
          If my job from project A is UNSTABLE, it won't be referenced as a downstream Job from dependency B (so building B will no trigger A). I have to build at least once in SUCCESS (by ex. by bypassing SONAR GATE) to see it in "Downstream Jobs" of my parent project.
           
          I'd like my parent "Downstream jobs" list updated for a project that is SUCCESS or UNSTABLE.
           
          Thanks
           
          {code:groovy}
          def call(body) {
            // evaluate the body block, and collect configuration into the object
            def pipelineParams = [:]
            body.resolveStrategy = Closure.DELEGATE_FIRST
            body.delegate = pipelineParams
            body()

            // Get Artifactory server instance, defined in the Artifactory Plugin administration page.
            def artifactory = Artifactory.server "ARTIFACTORY"

            def scmUrl

            def trimOrigin = {
              it.startsWith('origin/') ? it.trim() - 'origin/' : it.trim()
            }

            node('maven') {
              try {
                stage('Clone sources') {
                  // Keep only last 3 builds + disable concurrent builds
                  properties([
                      buildDiscarder(
                          logRotator(
                              artifactDaysToKeepStr: '',
                              artifactNumToKeepStr: '',
                              daysToKeepStr: '',
                              numToKeepStr: '3')
                      ),
                      disableConcurrentBuilds()
                  ])

                  testFailure = false
                  buildFailure = false

                  // MULTIBRANCH: Branch is part of the context: so use BRANCH_NAME
                  branchTobuild = env.BRANCH_NAME
                  echo "branchTobuild=${branchTobuild}"

                  // Scm url
                  scmUrl = scm.getUserRemoteConfigs()[0].getUrl()

                  // Clean
                  step([$class: 'WsCleanup', cleanWhenFailure: false])

                  // Get code from a Gitlab repository
                  git branch: trimOrigin(branchTobuild), credentialsId: 'jenkins', url: scmUrl

                  shortCommit = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%H'").trim()

                   // Get deployPath
                  deployPath = pipelineParams.deployPath ?: ""
                  echo "deployPath:${deployPath}"

                  // Is this component deployable (if not, no need to display deploy buttons in Slack)
                  deployable = pipelineParams.isDeployable ?: true
                  echo "deployable:${deployable}"
                }

                stage('Maven build') {
                  withMaven(maven: 'Maven 3.6.0', options: [junitPublisher(disabled: true)]) {
                    try {
                      sh 'mvn -U -T 2 clean deploy -DskipTests -Dmaven.javadoc.skip=true'
                    } catch (e) {
                      buildFailure = true
                      throw e
                    }
                  }
                }

                stage('Running tests') {
                  try {
                    sh 'mvn -T 2 --errors test -DfailIfNoTests=false -Dsurefire.useSystemClassLoader=false'
                  } catch (e) {
                    // if any exception occurs, mark the build as failed
                    testFailure = true
                    throw e
                  } finally {
                    junit(testResults: '**/surefire-reports/*xml', allowEmptyResults: true)
                  }
                }

                stage('SonarQube analysis') {
                  withSonarQubeEnv('Sonar') {
                    sh "mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar \
                       -Dsonar.sources='.' \
                       -Dsonar.inclusions='pom.xml,src/main/web/**,src/main/java/**' \
                       -Dsonar.exclusions='src/main/web/node_modules/**' \
                       -Dsonar.upsource.url='https://upsource.ehtrace.com' \
                       -Dsonar.upsource.project=${pomArtifactId} \
                       -Dsonar.upsource.revision=${shortCommit} \
                       -Dsonar.upsource.token='MHqwzb4IcQ'"
                  }
                }

                stage("Notify slack Quality Gate") {
                  timeout(time: 1, unit: 'HOURS') {
                    // Just in case something goes wrong, pipeline will be killed after a timeout
                    def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
                    if (qg.status != 'OK') {
                      currentBuild.result = 'UNSTABLE'
                      echo "Pipeline aborted due to quality gate failure: ${qg.status}"
                      notifySlackStatus('SONAR_QUALITY_GATE_FAILURE')
                    } else {
                      currentBuild.result = 'SUCCESS'
                      notifySlackStatus('SUCCESS')
                    }
                  }
                }
              } catch (Exception e) {
                // if any exception occurs, mark the build as failed
                echo e.message

                currentBuild.result = 'FAILURE'
                if (buildFailure == true) {
                  notifySlackStatus('BUILD_FAILURE')
                } else if (testFailure == true) {
                  notifySlackStatus('TEST_FAILURE')
                } else {
                  notifySlackStatus('FAILURE')
                }
                throw e // rethrow so the build is considered failed
              }
            }
          }
          {code}
          Cyrille Le Clerc made changes -
          Description Original: Hi,
           
          Here is my context.
          I have a pipeline with main steps:
           * mvn clean deploy
           * mvn test
           * sonar quality gate

          I choose to set currentBuild.result = 'UNSTABLE' if last step (quality gate from Sonar) is not OK.
          I want my dependencies to build automatically downstream projects when SNAPSHOT.
          Everything works well when quality gate is OK (means the job is SUCCESS):
          If my newly SUCCESSed project A contains SNAPSHOTed dependencies B, I can see on "Downstream Jobs" of this dependency B the newly build project.
          So, when I build this dependency B, on finished, job from project A is launched.
           
          BUT
           
          If my job from project A is UNSTABLE, it won't be referenced as a downstream Job from dependency B (so building B will no trigger A). I have to build at least once in SUCCESS (by ex. by bypassing SONAR GATE) to see it in "Downstream Jobs" of my parent project.
           
          I'd like my parent "Downstream jobs" list updated for a project that is SUCCESS or UNSTABLE.
           
          Thanks
           
          {code:groovy}
          def call(body) {
            // evaluate the body block, and collect configuration into the object
            def pipelineParams = [:]
            body.resolveStrategy = Closure.DELEGATE_FIRST
            body.delegate = pipelineParams
            body()

            // Get Artifactory server instance, defined in the Artifactory Plugin administration page.
            def artifactory = Artifactory.server "ARTIFACTORY"

            def scmUrl

            def trimOrigin = {
              it.startsWith('origin/') ? it.trim() - 'origin/' : it.trim()
            }

            node('maven') {
              try {
                stage('Clone sources') {
                  // Keep only last 3 builds + disable concurrent builds
                  properties([
                      buildDiscarder(
                          logRotator(
                              artifactDaysToKeepStr: '',
                              artifactNumToKeepStr: '',
                              daysToKeepStr: '',
                              numToKeepStr: '3')
                      ),
                      disableConcurrentBuilds()
                  ])

                  testFailure = false
                  buildFailure = false

                  // MULTIBRANCH: Branch is part of the context: so use BRANCH_NAME
                  branchTobuild = env.BRANCH_NAME
                  echo "branchTobuild=${branchTobuild}"

                  // Scm url
                  scmUrl = scm.getUserRemoteConfigs()[0].getUrl()

                  // Clean
                  step([$class: 'WsCleanup', cleanWhenFailure: false])

                  // Get code from a Gitlab repository
                  git branch: trimOrigin(branchTobuild), credentialsId: 'jenkins', url: scmUrl

                  shortCommit = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%H'").trim()

                   // Get deployPath
                  deployPath = pipelineParams.deployPath ?: ""
                  echo "deployPath:${deployPath}"

                  // Is this component deployable (if not, no need to display deploy buttons in Slack)
                  deployable = pipelineParams.isDeployable ?: true
                  echo "deployable:${deployable}"
                }

                stage('Maven build') {
                  withMaven(maven: 'Maven 3.6.0', options: [junitPublisher(disabled: true)]) {
                    try {
                      sh 'mvn -U -T 2 clean deploy -DskipTests -Dmaven.javadoc.skip=true'
                    } catch (e) {
                      buildFailure = true
                      throw e
                    }
                  }
                }

                stage('Running tests') {
                  try {
                    sh 'mvn -T 2 --errors test -DfailIfNoTests=false -Dsurefire.useSystemClassLoader=false'
                  } catch (e) {
                    // if any exception occurs, mark the build as failed
                    testFailure = true
                    throw e
                  } finally {
                    junit(testResults: '**/surefire-reports/*xml', allowEmptyResults: true)
                  }
                }

                stage('SonarQube analysis') {
                  withSonarQubeEnv('Sonar') {
                    sh "mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar \
                       -Dsonar.sources='.' \
                       -Dsonar.inclusions='pom.xml,src/main/web/**,src/main/java/**' \
                       -Dsonar.exclusions='src/main/web/node_modules/**' \
                       -Dsonar.upsource.url='https://upsource.ehtrace.com' \
                       -Dsonar.upsource.project=${pomArtifactId} \
                       -Dsonar.upsource.revision=${shortCommit} \
                       -Dsonar.upsource.token='MHqwzb4IcQ'"
                  }
                }

                stage("Notify slack Quality Gate") {
                  timeout(time: 1, unit: 'HOURS') {
                    // Just in case something goes wrong, pipeline will be killed after a timeout
                    def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
                    if (qg.status != 'OK') {
                      currentBuild.result = 'UNSTABLE'
                      echo "Pipeline aborted due to quality gate failure: ${qg.status}"
                      notifySlackStatus('SONAR_QUALITY_GATE_FAILURE')
                    } else {
                      currentBuild.result = 'SUCCESS'
                      notifySlackStatus('SUCCESS')
                    }
                  }
                }
              } catch (Exception e) {
                // if any exception occurs, mark the build as failed
                echo e.message

                currentBuild.result = 'FAILURE'
                if (buildFailure == true) {
                  notifySlackStatus('BUILD_FAILURE')
                } else if (testFailure == true) {
                  notifySlackStatus('TEST_FAILURE')
                } else {
                  notifySlackStatus('FAILURE')
                }
                throw e // rethrow so the build is considered failed
              }
            }
          }
          {code}
          New: Hi,
           
          Here is my context.
          I have a pipeline with main steps:
           * mvn clean deploy
           * mvn test
           * sonar quality gate

          I choose to set currentBuild.result = 'UNSTABLE' if last step (quality gate from Sonar) is not OK.
          I want my dependencies to build automatically downstream projects when SNAPSHOT.
          Everything works well when quality gate is OK (means the job is SUCCESS):
          If my newly SUCCESSed project A contains SNAPSHOTed dependencies B, I can see on "Downstream Jobs" of this dependency B the newly build project.
          So, when I build this dependency B, on finished, job from project A is launched.
           
          BUT
           
          If my job from project A is UNSTABLE, it won't be referenced as a downstream Job from dependency B (so building B will no trigger A). I have to build at least once in SUCCESS (by ex. by bypassing SONAR GATE) to see it in "Downstream Jobs" of my parent project.
           
          I'd like my parent "Downstream jobs" list updated for a project that is SUCCESS or UNSTABLE.
           
          Thanks
           
          {code:groovy}
          def call(body) {
            // evaluate the body block, and collect configuration into the object
            def pipelineParams = [:]
            body.resolveStrategy = Closure.DELEGATE_FIRST
            body.delegate = pipelineParams
            body()

            // Get Artifactory server instance, defined in the Artifactory Plugin administration page.
            def artifactory = Artifactory.server "ARTIFACTORY"

            def scmUrl

            def trimOrigin = {
              it.startsWith('origin/') ? it.trim() - 'origin/' : it.trim()
            }

            node('maven') {
              try {
                stage('Clone sources') {
                  // Keep only last 3 builds + disable concurrent builds
                  properties([
                      buildDiscarder(
                          logRotator(
                              artifactDaysToKeepStr: '',
                              artifactNumToKeepStr: '',
                              daysToKeepStr: '',
                              numToKeepStr: '3')
                      ),
                      disableConcurrentBuilds()
                  ])

                  testFailure = false
                  buildFailure = false

                  // MULTIBRANCH: Branch is part of the context: so use BRANCH_NAME
                  branchTobuild = env.BRANCH_NAME
                  echo "branchTobuild=${branchTobuild}"

                  // Scm url
                  scmUrl = scm.getUserRemoteConfigs()[0].getUrl()

                  // Clean
                  step([$class: 'WsCleanup', cleanWhenFailure: false])

                  // Get code from a Gitlab repository
                  git branch: trimOrigin(branchTobuild), credentialsId: 'jenkins', url: scmUrl

                  shortCommit = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%H'").trim()

                   // Get deployPath
                  deployPath = pipelineParams.deployPath ?: ""
                  echo "deployPath:${deployPath}"

                  // Is this component deployable (if not, no need to display deploy buttons in Slack)
                  deployable = pipelineParams.isDeployable ?: true
                  echo "deployable:${deployable}"
                }

                stage('Maven build') {
                  withMaven(maven: 'Maven 3.6.0', options: [junitPublisher(disabled: true)]) {
                    try {
                      sh 'mvn -U -T 2 clean deploy -DskipTests -Dmaven.javadoc.skip=true'
                    } catch (e) {
                      buildFailure = true
                      throw e
                    }
                  }
                }

                stage('Running tests') {
                  try {
                    sh 'mvn -T 2 --errors test -DfailIfNoTests=false -Dsurefire.useSystemClassLoader=false'
                  } catch (e) {
                    // if any exception occurs, mark the build as failed
                    testFailure = true
                    throw e
                  } finally {
                    junit(testResults: '**/surefire-reports/*xml', allowEmptyResults: true)
                  }
                }

                stage('SonarQube analysis') {
                  withSonarQubeEnv('Sonar') {
                    sh "mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar \
                       -Dsonar.sources='.' \
                       -Dsonar.inclusions='pom.xml,src/main/web/**,src/main/java/**' \
                       -Dsonar.exclusions='src/main/web/node_modules/**' \
                       -Dsonar.upsource.url='https://upsource.ehtrace.com' \
                       -Dsonar.upsource.project=${pomArtifactId} \
                       -Dsonar.upsource.revision=${shortCommit} \
                       -Dsonar.upsource.token='***********'"
                  }
                }

                stage("Notify slack Quality Gate") {
                  timeout(time: 1, unit: 'HOURS') {
                    // Just in case something goes wrong, pipeline will be killed after a timeout
                    def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
                    if (qg.status != 'OK') {
                      currentBuild.result = 'UNSTABLE'
                      echo "Pipeline aborted due to quality gate failure: ${qg.status}"
                      notifySlackStatus('SONAR_QUALITY_GATE_FAILURE')
                    } else {
                      currentBuild.result = 'SUCCESS'
                      notifySlackStatus('SUCCESS')
                    }
                  }
                }
              } catch (Exception e) {
                // if any exception occurs, mark the build as failed
                echo e.message

                currentBuild.result = 'FAILURE'
                if (buildFailure == true) {
                  notifySlackStatus('BUILD_FAILURE')
                } else if (testFailure == true) {
                  notifySlackStatus('TEST_FAILURE')
                } else {
                  notifySlackStatus('FAILURE')
                }
                throw e // rethrow so the build is considered failed
              }
            }
          }
          {code}
          Arnaud Héritier made changes -
          Assignee Original: Cyrille Le Clerc [ cleclerc ]

            Unassigned Unassigned
            bentocquec benjamin tocquec
            Votes:
            3 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated: