2
votes

I've created a pipeline in Jenkins new Blue Ocean interface and would like to have it run every hour. I don't see an option in the UI to add a build schedule. I do see it in the classic UI, but the setting isn't editable. What is the recommend approach to schedule a pipeline to run on a schedule rather than a commit?

Here is a screenshot of the settings I see in Blue ocean.

In this screenshoot you can see the option to "View Configuration". The setting for scheduling the job are there but not editable.

2
Can you please add the screenshot too.Barney
I found a work around that seems less then ideal. I created a separate freestyle project that triggers the pipeline project every hour. It accomplishes what I want, but it would be cleaner if I could do it in the pipeline configuration.Bruce McCleave

2 Answers

0
votes

These can be done in two ways depending on the structure which your Jenkinsfile follows:

1) Scripted Jenkinsfile approach :

node('node_name') {
    properties(
        [
        pipelineTriggers([cron('0 0 * ? * * *')])
        ]
    )

2) Declarative Jenkinsfile approach :

triggers {
    cron('0 0 * ? * * *')
}

Hope this will help you, feel free to contact in case of queries.

0
votes

For scripted pipelines, this feature is poorly implemented out-of-the-box (as of 2019).

The Ugly

The simplest way to do it (e.g. for the schedule "H 10 * * *") is to put the following in your Jenkinsfile:

node {
  properties([
    pipelineTriggers([cron("H 10 * * *")])
  ])
}

In BlueOcean, every branch and every pull request counts as its own job -- so if you follow standard git workflow, the above code will create no less than three cron jobs:

  1. The feature branch you push, even though it hasn't been merged
  2. The pull request branch, whether or not you merge it
  3. The master branch (if/when you merge the feature branch)

There is no way to undo this damage unless you push more commits to the feature branch and keep the pull request open under the same number -- otherwise you will be configuring a different job than the one with the cron script. You can only fix it in the Jenkins console, since (as you noted), the BlueOcean setup will block your access to the job settings like it would in the non-BlueOcean Jenkins UI.

The Bad

A slightly smarter way to do it is to make the schedule depend on what branch is being used.

def mySchedule = BRANCH_NAME == "master" ? "H 10 * * *" : ""

node {
  properties([
    pipelineTriggers([cron(mySchedule)])
  ])
}

This can avoid "The Ugly" situation, but it can't undo any previous damage. It certainly can't stop anyone from removing the conditional in their own pull request (i.e. from accidentally or unwittingly going back to "The Ugly").

The Good

The safe way to do this requires accessing the Jenkins API directly:

import hudson.triggers.TimerTrigger

//          v-- a Map of jobName to schedule string
def setCron(whitelistedCronSchedules = [:])
  // only apply cron settings when running on master -- i.e. on merge to master
  if ("${env.BRANCH_NAME}" == MASTER_BRANCH) {

    // navigate up to the parent job, then iterate over all its child jobs,
    // setting timers from the whitelist as we go
    def thisJob = Jenkins.get().getItemByFullName(env.JOB_NAME)

    for (Item ajob in thisJob.getParent().getAllJobs()) {
      // you could optionally check ajob.getTriggers()[0].spec to see
      //   if the schedule is already set to what you want it to be

      // get job schedule from the whitelist, or null if there is none
      def jobName = java.net.URLDecoder.decode(ajob.getName(), "UTF-8")
      def mySchedule = whitelistedCronSchedules.get(jobName, null)

      // Triggers are set all at once: no triggers, or just one with our schedule
      def triggersToSet = mySchedule == null ? [] : [new hudson.triggers.TimerTrigger(mySchedule)]
      ajob.setTriggers(triggersToSet)
    }
  }
}

node {
    // example usage:
    setCron(["master": "H 10 * * *"]) // turns on cron for just the master branch, off for all others

    // alternately,
    setCron()                         // turns off cron for ALL jobs for this repo 
}