Skip to content

Instantly share code, notes, and snippets.

@jhoblitt
Last active June 13, 2023 09:34
Show Gist options
  • Save jhoblitt/5f812cba39f0ec3c2e01f00d97d379a2 to your computer and use it in GitHub Desktop.
Save jhoblitt/5f812cba39f0ec3c2e01f00d97d379a2 to your computer and use it in GitHub Desktop.
Recursively listing jobs in the Cloudbees folder plugin
#!/usr/bin/env ruby
require 'benchmark'
require 'jenkins_api_client'
require 'json'
@client = JenkinsApi::Client.new(
:server_url => 'https://example.org',
:username => 'jhoblitt',
:password => '...',
#:log_level => Logger::DEBUG,
)
def api
def find_jobs(jobs, folder_path = nil)
# path should not have a leading `/`
found = []
jobs.each do |job|
name = job['name']
if folder_path
# add folder path to job name
name = "#{folder_path}/#{job['name']}"
job['name'] = name
end
found << job
if job['_class'] == 'com.cloudbees.hudson.plugins.folder.Folder'
# mangle "folder" path into "API" path
api_path = '/job/' + name.split('/').join('/job/')
folder = @client.api_get_request(api_path, "tree=jobs[name]")["jobs"]
found += find_jobs(folder, name)
end
end
found
end
jobs = @client.api_get_request("", "tree=jobs[name]")["jobs"]
find_jobs(jobs)
end
def groovy
# based on groovy code I hacked together for recursively listing jobs/folders
# for the puppet jenkins module
# https://github.com/jenkinsci/puppet-jenkins/blob/master/files/puppet_helper.groovy
text = @client.exec_script(<<'EOS')
def Map findJobs(Object obj, String namespace = null) {
def found = [:]
// groovy apparently can't #collect on a list and return a map?
obj.items.each { job ->
// a possibly better approach would be to walk the parent chain from //
// each job
def path = job.getName()
if (namespace) {
path = "${namespace}/" + path
}
found[path] = job
// intentionally not using `instanceof` here so we don't blow up if the
// cloudbees-folder plugin is not installed
if (job.getClass().getName() == 'com.cloudbees.hudson.plugins.folder.Folder') {
found << findJobs(job, path)
}
}
found
}
void job_list_json() {
def jobs = findJobs(Jenkins.getInstance())
def allInfo = jobs.collect { path, job ->
// at least these job classes do not respond to respond to #isDisabled:
// - org.jenkinsci.plugins.workflow.job.WorkflowJob
// - com.cloudbees.hudson.plugins.folder.Folder
def enabled = false
if (job.metaClass.respondsTo(job, 'isDisabled')) {
enabled = !job.isDisabled()
}
[
_class: job.getClass().toString(),
name: path,
]
}
def builder = new groovy.json.JsonBuilder(allInfo)
out.println(builder.toPrettyString())
}
job_list_json()
EOS
JSON.parse(text)
end
n = 10
Benchmark.bmbm do |x|
x.report('api:') { n.times { api } }
x.report('groovy:') { n.times { groovy } }
end
Rehearsal -------------------------------------------
api: 0.360000 0.070000 0.430000 ( 33.993842)
groovy: 0.060000 0.010000 0.070000 ( 4.433300)
---------------------------------- total: 0.500000sec
user system total real
api: 0.340000 0.080000 0.420000 ( 31.899548)
groovy: 0.060000 0.000000 0.060000 ( 4.385597)
# example output showing the number of jobs/folders on the jenkins instance the benchmark was run against
{"name"=>"backup", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"backup/build-sqre-github-snapshot", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"backup/jenkins-ebs-snapshot", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"backup/nightly-sqre-github-snapshot", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"ci-ci", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"ci-ci/jenkins-dm-jobs", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"ci-ci/test-freestyle", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"ci-ci/test-pipeline", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"ci-ci/test-pipeline-docker", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"ci-ci/test-pipeline-write", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"ci_hsc", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"cowboy", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"cowboy/stack", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"dax_webserv", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"lsst_apps", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"lsst_distrib", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"lsst_py3", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"lsst_sims", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"qserv", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"qserv/docker", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"qserv/docker/build", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"qserv_distrib", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"release", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"release/build-publish-tag", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"release/docker", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"release/docker/build", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"release/docker/newinstall", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"release/docker/prepare", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"release/run-publish", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"release/run-rebuild", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"release/tag-git-repos", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"release/weekly-release", "_class"=>"class org.jenkinsci.plugins.workflow.job.WorkflowJob"}
{"name"=>"seeds", "_class"=>"class com.cloudbees.hudson.plugins.folder.Folder"}
{"name"=>"seeds/dm-jobs", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"sims_utils", "_class"=>"class hudson.model.FreeStyleProject"}
{"name"=>"stack-os-matrix", "_class"=>"class hudson.matrix.MatrixProject"}
{"name"=>"stack-osx", "_class"=>"class hudson.matrix.MatrixProject"}
{"name"=>"validate_drp", "_class"=>"class hudson.matrix.MatrixProject"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment