1

I have a job defined as a declarative pipeline that gets triggered by a number of different upstream jobs. Depending on which upstream job triggered my job, I don't necessarily need to run all of the stages in my pipeline, so I want to specify a list of triggers for each stage.

I was hoping to use a when clause and triggeredBy conditions to determine when each stage runs, but the documentation isn't very detailed:

triggeredBy

Execute the stage when the current build has been triggered by the param given. For example:

when { triggeredBy 'SCMTrigger' }

when { triggeredBy 'TimerTrigger' }

when { triggeredBy 'UpstreamCause' }

when { triggeredBy cause: "UserIdCause", detail: "vlinde" }

Is there an 'UpstreamCause' equivalent to the example for 'UserIdCause' that would allow me to specify which upstream cause should trigger a specific stage? If so, what is the exact syntax? Basically I want to do something like:

when {
    anyOf {
        triggeredBy cause: 'UpstreamCause', detail: 'Job A'
        triggeredBy cause: 'UpstreamCause', detail: 'Job C'
    }
}

I'm also open to other approaches for accomplishing this.

1 Answer 1

1

Is there an 'UpstreamCause' equivalent to the example for 'UserIdCause' that would allow me to specify which upstream cause should trigger a specific stage?

Unfortunately, not in native Declarative syntax.

As you can see from the source code, UserIdCause is special-cased, but no other cause is:

    static boolean shouldRunBeAllowed(Cause causeClass, String cause, String detail){
        if( causeClass instanceof Cause.UserIdCause && Cause.UserIdCause.simpleName == cause){
            return detail == null || causeClass.userId == detail
        }else {
            return causeClass.class.simpleName.matches("(?i)\\.*${cause}.*")
        }
    }

So if you want to trigger conditionally based on which job triggered the build, you'll need to use Scripted syntax. For instance (I haven't tested this so no guarantees it will work without debugging):

script {
  def myJob = 'put-your-job-name-here'
  def causes = currentBuild.rawBuild.getCauses()
  def triggeredByMyJob = causes.any { cause->
    cause.class.toString().contains("UpstreamCause")) && cause.upstreamProject == myJob
  }

  if (triggeredByMyJob) {
    // put steps to execute when triggered by your job here
  } else {
    // put steps to execute when NOT triggered by your job here
  }
} 

However, there's potentially a much easier way, although it's not strictly what you asked for: Give your downstream job a boolean parameter, for the sake of example let's call it runMyStages, and use a when clause to conditionally execute stages based on whether runMyStages is true or false. Then in your upstream jobs, you can set that parameter in your build step: build(job: 'downstream-job-name', parameters: [booleanParam('runMyStages', false)]).

1
  • The second idea is interesting, but the way our jobs are currently structured I have the upstream triggers defined in the downstream job, rather than using a build step in the upstream jobs. I might try using the first approach at the start of my job and setting some environment variables based on each upstream cause found, so that I can look at those in a when for each stage.
    – c32hedge
    Commented Feb 24, 2021 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.