ghale / gradle-jenkins-plugin

Gradle plugin to programmatically configure Jenkins jobs.
123 stars 42 forks source link

Nested CloudBees Folders Question / Issue? #70

Open philbeiler opened 8 years ago

philbeiler commented 8 years ago

I'm trying to figure out how to do nested folders, and not having much success. Top level folders work do work fine with this approach.

My build.gradle simply pulls in a bunch of groovy/dsl scripts using this syntax:

dsl fileTree('jobs').include('*.groovy')

My nested folder looks like this.

folder('project-a') {
    displayName('Project A')
    description('Folder for project A')
}

folder('project-a/testing') {
    displayName('Project Testing')
    description('Testing for project A')
}

Gradle is dumping this in the logs....

14:36:25.091 [DEBUG] [org.apache.http.impl.conn.DefaultClientConnection] Sending request: POST /createItem?name=project-a%2Ftesting HTTP/1.1 14:36:25.097 [DEBUG] [org.apache.http.impl.conn.DefaultClientConnection] Receiving response: HTTP/1.1 400 Bad Request

What am I missing? Thanks.

mpettigr commented 8 years ago

I'm hitting the same issue. Using the jenkins { dsl { job { flow,

jenkins {

dsl { ... // Ensure folder is for subsequent job building. folder("${folderName}") { description('foobar.') }

job("${folderName}/${jobName}") {

The folder will be created but I can't reference the folder in a job name. This fails for both the updateJenkinsItems and dumpJenkinsItems. This flow does work in job-dsl proper. I'm using the 1.3.2 gradle jenkins plugin ( which uses job-dsl-core 1.42).

Philbeier, if your dsl {} config is inside a jobs {} configuration, the folder construct won't work but if you move the dsl to the top-level, i.e., jenkins { dsl { folder() }} that approach should work but unfortunately, you can't reference the folder in a job definition. :-(

mpettigr commented 8 years ago

JUST figured out some sauce to workaround the job-dsl folder issue using serviceOverrides. serviceoverrides is undoc'ed but search in "issues" for details.

jenkins {
...
  // NOTE: This will only work 1 folder deep.  TODO: Follow pattern for 2+ deep version. 
  def defaultServiceOverrides = { folder, jobName ->
    return {
      create = ["uri": "/jenkins/job/${folder}/createItem", params: [ name: "${jobName}" ] ]
      update = ["uri": "/jenkins/job/${folder}/job/${jobName}/config.xml"]
      get = ["uri": "/jenkins/job/${folder}/job/${jobName}/config.xml"]
      delete = ["uri": "/jenkins/job/${folder}/job/${jobName}/doDelete"]
    }
  }
...
  dsl {
    // Ensure folder is present for subsequent job building.
    // NOTE: job-dsl folder command does not work in
    // jobs { jobName { dsl { folder <- doesn't work }}} construct
    // so need to leave it separate top-level dsl config here.
    //
    folder("${folderName}") {
      description('EDIF sample data extraction effort.')
    }
  }

...

  jobs {
    "${jobName}" {
      dsl fileTree('.').include("${jobName}.groovy")
      // place job in appropriate folder.  gradle jenkins plugin doesn't support
      // job-dsl job command with folder in the name like foo/bar.
      // Use serviceOverrides as a workaround.
      serviceOverrides defaultServiceOverrides(folderName, jobName)
    }
  }
   ...

I have variables folderName and jobName defined elsewhere but hopefully you get the gist. The dsl file creates a job at the root level of Jenkins. You can see this when you run dumpJenkinsItem. But, the serviceOverrides effectively moves the job into the folder $folderName.

So, folders aren't first class citizens in the gradle jenkins plugin :-( but there are workarounds. NOTE: This approach works for the XML config flow as well. Place the serviceOverrides clause after the definition configuration.

You can always just use gradle and job-dsl directly ( see https://github.com/sheehan/job-dsl-gradle-example ) BUT not having to deal with seed jobs plus the tasks added in this plugin still make it worth it for me. :-) . Nice job, Gary!

mpettigr commented 8 years ago

Last remark and I hope this issue is resolved well since it basically means that job names must be unique across all jenkins jobs since you can't use folders to provide a namespace to isolate job names. :-(

dcendents commented 7 years ago

Well in fact you can create jobs with the same name in different folders with the following approach:

  jobs {
    "${folderName}-${jobName}" {
      ...
      serviceOverrides defaultServiceOverrides(folderName, jobName)
    }
  }

if you run dumpJenkinsItems, you will get folderName-jobName.xml, so unique names for each config file.

But when you run updateJenkinsItems the override kicks in and it correctly create/update folderName/jobName, assuming multiple jobs with jobName will be created in different folders.