Jenkins: Generating Blue Ocean URLs

I just finished setting up a Jenkins build server for a client. This client wanted to use Blue Ocean, the new attractive and streamlined user interface for Jenkins Pipeline projects.

Once Blue Ocean is installed, users can switch between the standard Jenkins interface and the Blue Ocean interface at will. However, many users interact with Jenkins using direct links on GitHub, in Slack, or over email. If your team relies on the BUILD_URL environment variable to generate these links, you've probably noticed that you always end up using the default user interface. Since my client wanted to use the Blue Ocean interface by default, using links to the default interface wasn't an appealing option.

Generating Blue Ocean URLs

Unfortunately, each interface uses a different URL generation scheme. Much to my disappointment, we can't just add a /blue to the end of our Jenkins URL in the system configuration. After searching I initially came across the Display URL for Blue Ocean Jenkins plugin, which seems to be automatically installed with Blue Ocean. The documentation is pretty sparse, so I was confused by the usage.

After some stumbling and experimentation, I realized that this plugin simply provides additional environment variables (e.g BUILD_URL) that we can use in our Jenkins builds. By using the Display URL for Blue Ocean environment variables, I was able to get my plugins to provide Blue Ocean URLs in Slack and GitHub.

The plugin provides three useful environment variables:

  1. RUN_DISPLAY_URL: provides a URL to the build's result page
  2. RUN_CHANGES_DISPLAY_URL: provides a URL to the build changes page
  3. JOB_DISPLAY_URL: provides a URL to the job page

Example Usage

To generate a Blue Ocean URL, simply replace instances of BUILD_URL with RUN_DISPLAY_URL. For example, my GitHub status pipeline library function provides a link to the build as a back reference:

step([
    $class: 'GitHubCommitStatusSetter',
    reposSource: [$class: "ManuallyEnteredRepositorySource", url: repoUrl],
    commitShaSource: [$class: "ManuallyEnteredShaSource", sha: commitSha],
    errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
    contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
    statusBackrefSource: [$class: "ManuallyEnteredBackrefSource", backref: "${env.BUILD_URL}"],
    statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
  ])

I simply change the statusBackrefSource to reference ${env.RUN_DISPLAY_URL} instead:

step([
    $class: 'GitHubCommitStatusSetter',
    reposSource: [$class: "ManuallyEnteredRepositorySource", url: repoUrl],
    commitShaSource: [$class: "ManuallyEnteredShaSource", sha: commitSha],
    errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
    contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
    statusBackrefSource: [$class: "ManuallyEnteredBackrefSource", backref: "${env.RUN_DISPLAY_URL}"],
    statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
  ])

Supporting Both Blue Ocean and Standard Jenkins URLs

There are some cases where you need to select between either a Blue Ocean URL or a standard Jenkins URL. For example, I maintain a Jenkins Pipeline Library that is used for both internal and client projects. I can't always rely on a particular server instance to have Blue Ocean installed or for it to be the preferred interface.

To provide flexibility for the library users, I have created an argument to switch between Blue Ocean and standard URLs. Here's my setGithubStatus function with URL switching support:

def call(String context, String message, String state, Boolean blueOcean = true) {
  // workaround https://issues.jenkins-ci.org/browse/JENKINS-38674
  repoUrl = gitRepoURL()
  commitSha = gitCommitHash()

  String buildResultUrl = "${env.BUILD_URL}"

  if(blueOcean)
  {
    buildResultUrl = "${env.RUN_DISPLAY_URL}"
  }

  echo "Updating status for URL: $repoUrl // commit: $commitSha // context: $context"

  step([
    $class: 'GitHubCommitStatusSetter',
    reposSource: [$class: "ManuallyEnteredRepositorySource", url: repoUrl],
    commitShaSource: [$class: "ManuallyEnteredShaSource", sha: commitSha],
    errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
    contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
    statusBackrefSource: [$class: "ManuallyEnteredBackrefSource", backref: "${buildResultUrl}"],
    statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
  ])
}

By default, this function will generate URLs for Blue Ocean (blueOcean = true), but the behavior can be overridden if the function is called with blueOcean set to false. Using this method, I provide generic URL reporting and control the final customer-facing behavior in the build's Jenkins pipeline file.

Further Reading