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

Execute alternative step(s) if stage is filtered by a when condition

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      Currently if a when condition filters a stage, there's no way to execute a step in response to that, it just treats it like it never existed. It would be useful to allow something like post.notBuilt (or a new post condition) to execute for a filtered stage (stage.when only - would not make sense in a pipeline.when condition).

      My use case is a pipeline that runs a series of verification stages against a Gerrit change (like a pull request), using the Gerrit Code Review plugin to set the status of one or more "Checks". Not all stages have to run on every change though, so I'd rather be more intelligent about skipping stages that don't apply for a change, and still report that feedback in the change UI.

      pipeline {
          agent any
          stages {
              // other stages
              stage("Style") {
                  when {
                      expression { false }
                      // For example, only if source files changed:
                      changeset '**/src/*/java/**'
                  }
                  steps {
                      // run checkstyle, lint, etc
                  }
                  post {
                      notBuilt {
                          // Set PR stage results to "Not Relevant" to show that it was skipped
                          gerritCheck checks: ["jenkins:style": "NOT_RELEVANT"]
                          // This does not execute because the stage was skipped.
                      }
                      successful {
                          gerritCheck checks: ["jenkins:style": "SUCCESS"]
                      }
                      unsuccessful {
                          gerritCheck checks: ["jenkins:style": "FAILED"]
                      }
                  }
              }
          }
      }
      

      I understand the post.notBuilt block has a different meaning – specifically it executes only if the stage executes and the stage/build result is NOT_BUILT. And that is different from a stage being skipped altogether.

      The only other way I can see to achieve this would be another stage that runs with inverted conditions (results in duplication of the when conditions), or by setting an environment variable when the target stage runs, that is then checked in another stage after it (if not set, it didn't run, so mark it NOT_RELEVANT). These solutions all come across as hacks and overly verbose, when all I really need to do is execute some step when the stage would be filtered.

      Another option could be something like a new when.otherwise block that executes a step in place of the stage, if the conditions failed:

                  when {
                      expression { false }
      
                      otherwise {
                          gerritCheck checks: ["jenkins:style": "NOT_RELEVANT"]
                      }
                  }
      

        Attachments

          Activity

          Hide
          jhansche Joe Hansche added a comment -

          The simplest solution (but still a bit too verbose IMO), looks like:

              stage("Style") {
                  environment { DID_RUN = "false" } // will be overridden if the nested stage executes
                  stages {
                      stage("Style") { // the real stage
                          when {
                              // conditions... (such as only if source files changes, but not if unrelated files changed, such as text files, etc)
                          }
                          steps {
                              // run the lint/style tasks
                              ...
                              // The magic: if it runs, env var gets updated, and that will skip the next stage.
                              // If it doesn't run, it keeps the "false" value from above, and then the next stage will run instead.
                              script { env.DID_RUN = "true" }
                          }
                          post {
                              // gerritCheck to set SUCCESS/FAILED based on stage result.
                          }
                      }
                      stage("skipped") { // if it didn't run
                          when { environment { name: "DID_RUN", value: "false" } }
                          steps { gerritCheck checks: ["style": "NOT_RELEVANT"] }
                  }
              }
          

          Could be simplified slightly – for example, by removing the environment{} line in the parent stage, and change the "skipped" stage to:

           when { not { environment { name: "DID_RUN", value: "true" } } } 

          or

           when { expression { env.DID_RUN != "true" } } 
          Show
          jhansche Joe Hansche added a comment - The simplest solution (but still a bit too verbose IMO), looks like: stage( "Style" ) { environment { DID_RUN = " false " } // will be overridden if the nested stage executes stages { stage( "Style" ) { // the real stage when { // conditions... (such as only if source files changes, but not if unrelated files changed, such as text files, etc) } steps { // run the lint/style tasks ... // The magic: if it runs, env var gets updated, and that will skip the next stage. // If it doesn't run, it keeps the " false " value from above, and then the next stage will run instead. script { env.DID_RUN = " true " } } post { // gerritCheck to set SUCCESS/FAILED based on stage result. } } stage( "skipped" ) { // if it didn't run when { environment { name: "DID_RUN" , value: " false " } } steps { gerritCheck checks: [ "style" : "NOT_RELEVANT" ] } } } Could be simplified slightly – for example, by removing the environment{} line in the parent stage, and change the "skipped" stage to: when { not { environment { name: "DID_RUN" , value: " true " } } } or when { expression { env.DID_RUN != " true " } }

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            jhansche Joe Hansche
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Dates

              Created:
              Updated: