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

Stage result not always considered for stage post action

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: Critical Critical
    • pipeline
    • Jenkins 2.319.1, Windows 10

      I noticed a strange behavior when using post actions for stages. It seems like the stage result for a post action is not considered if there is already a worse overall build result set.

      According to the doc, the post success block should:

      Only run the steps in post if the current Pipeline's or stage's run has a "success" status, typically denoted by blue or green in the web UI.

      It rather looks like that it only runs the steps if the current pipeline status is SUCCESS or not set and the stage is also SUCCESS. If the stage is SUCCESS but not the pipeline status it would not be executed.

      This seems very unintuitive because you would think that if a stage is successful, the success stage post action would also always be triggered. Therefore, the post actions for steps is actually not usable if the overall build result is set to e.g., UNSTABLE.

      Example

      I added a small example where such a behavior can be seen:

      pipeline {
          agent any
          stages {
              stage ('A') {
                  steps {
                      unstable('Step unstable')
                  }
              }
              
              stage ('B') {
                  steps {
                      echo('Step B')
                  }
                  post {
                      success {
                          echo "Success B!"
                      }
                      unstable {
                          echo "Unstable B!"
                      }   
                  }
              }
          }
      }
      

      Stage A is executed and the stage result as well as the pipeline result is then set to UNSTABLE. Afterwards stage B is executed. It is successful, but only the unstable post action of stage B is executed instead of its success stage.

       

      I also found some issues which sound similar to my described problem, like JENKINS-39203. But in my case it's only about the execution and not the visualization. There is also a comment at the end describing something similar....

          [JENKINS-68281] Stage result not always considered for stage post action

          A related scenario, where the run result is FAILURE but the stage result is SUCCESS, may have been broken by Pipeline: Declarative PR #3229 for JENKINS-56544. Before that, the boolean meetsCondition(@Nonnull WorkflowRun r, Object context, Throwable error) method in Success.groovy used to return true if WorkflowRun r had a FAILURE result, Object context was a Stage, and Throwable error (which I believe comes from the stage) was null. After PR #3229, Success.meetsCondition ignored Object context altogether.

          The Success.meetsCondition method was then changed again in PR #330 for JENKINS-57826. It now forwards all of its parameters to BuildCondition.combineResults, which in turn calls BuildCondition.getCombinedResult; but this always combines getFlowExecutionResult(run), run.getResult(), and the result of Throwable error by calling Result.combine, which returns SUCCESS only if both inputs are SUCCESS.

          The meetsCondition method is called from AbstractBuildConditionResponder.hasSatisfiedConditions from Root.hasSatisfiedConditions from ModelInterpreter.executeSingleStage. If at least one post condition matches, then ModelInterpreter.executeSingleStage calls ModelInterpreter.runPostConditions, which calls BuildCondition.getCombinedResult again and temporarily sets runWrapper.rawBuild.@result to that value.

          If changing the Success.meetsCondition logic is now considered too risky for compatibility, I think it would be possible to add another class StageSuccess that considers only the result of the stage and ignores the result of the run. ModelInterpreter.runPostConditions would still temporarily set runWrapper.rawBuild.@result to a combined value but it probably has the same value already.

          There seems to be an additional bug in that Object context is sometimes a Stage instance and sometimes the name of the stage as a String:

          Kalle Niemitalo added a comment - A related scenario, where the run result is FAILURE but the stage result is SUCCESS, may have been broken by Pipeline: Declarative PR #3229 for JENKINS-56544 . Before that, the boolean meetsCondition(@Nonnull WorkflowRun r, Object context, Throwable error) method in Success.groovy used to return true if WorkflowRun r had a FAILURE result, Object context was a Stage, and Throwable error (which I believe comes from the stage) was null. After PR #3229, Success.meetsCondition ignored Object context altogether. The Success.meetsCondition method was then changed again in PR #330 for JENKINS-57826 . It now forwards all of its parameters to BuildCondition.combineResults , which in turn calls BuildCondition.getCombinedResult ; but this always combines getFlowExecutionResult(run) , run.getResult() , and the result of Throwable error by calling Result.combine , which returns SUCCESS only if both inputs are SUCCESS. The meetsCondition method is called from AbstractBuildConditionResponder.hasSatisfiedConditions from Root.hasSatisfiedConditions from ModelInterpreter.executeSingleStage . If at least one post condition matches, then ModelInterpreter.executeSingleStage calls ModelInterpreter.runPostConditions , which calls BuildCondition.getCombinedResult again and temporarily sets runWrapper.rawBuild.@result to that value. If changing the Success.meetsCondition logic is now considered too risky for compatibility, I think it would be possible to add another class StageSuccess that considers only the result of the stage and ignores the result of the run. ModelInterpreter.runPostConditions would still temporarily set runWrapper.rawBuild.@result to a combined value but it probably has the same value already. There seems to be an additional bug in that Object context is sometimes a Stage instance and sometimes the name of the stage as a String: Stage instance: ModelInterpreter.executeSingleStage calls Root.hasSatisfiedConditions , which calls AbstractBuildConditionResponder.satisfiedConditions , which calls BuildCondition.meetsCondition(Object runWrapperObj, Object context, Throwable error) , which calls BuildCondition.meetsCondition(WorkflowRun r, Object context, Throwable error) , which is overridden by Success.meetsCondition , which calls BuildCondition.combineResults , which calls BuildCondition.getCombinedResult , which does not recognize the Stage type. Name of the stage as a String: ModelInterpreter.runPostConditions calls BuildCondition.getCombinedResult , which recognizes the String type.

          Kalle Niemitalo added a comment - - edited

          This issue is a duplicate of JENKINS-57801, like JENKINS-61405.

          I filed JENKINS-68288 for the Object context type mismatch.

          Kalle Niemitalo added a comment - - edited This issue is a duplicate of JENKINS-57801 , like JENKINS-61405 . I filed JENKINS-68288 for the Object context type mismatch.

            Unassigned Unassigned
            codetent Christoph
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: