class BaseSystemTest(unittest.TestCase): def setUp(self): self.jenkins = Jenkins('http://localhost:8080') self._delete_all_jobs() self._delete_all_views() def tearDown(self): pass def _delete_all_jobs(self): self.jenkins.poll() for name in self.jenkins.get_jobs_list(): self.jenkins.delete_job(name) def _delete_all_views(self): all_view_names = self.jenkins.views.keys()[1:] for name in all_view_names: del self.jenkins.views[name] def _create_job(self, name='whatever', config=EMPTY_JOB): job = self.jenkins.create_job(name, config) self.jenkins.poll() return job def assertJobIsPresent(self, name): self.jenkins.poll() self.assertTrue(name in self.jenkins, 'Job %r is absent in jenkins.' % name) def assertJobIsAbsent(self, name): self.jenkins.poll() self.assertTrue(name not in self.jenkins, 'Job %r is present in jenkins.' % name)
class JenkinsApi(object): def __init__(self, url, username, token): logger.debug('create jenkins api instance') logger.debug('url %s username %s token %s', url, username, token) self.jenkins = Jenkins(url, username, token) def has_job(self, name): logger.info('check task "%s" exists', name) result = self.jenkins.has_job(name) logger.debug('return result %s', result) return result def create_job(self, name, xml): logger.debug('create task "%s", xml %s', name, xml) return self.jenkins.create_job(name, xml) def delete_job(self, name): logger.debug('upgrade task "%s", delete it', name) self.jenkins.delete_job(name) def get_config(self, name): logger.debug('get task task "%s"', name) return self.jenkins[name].get_config() def update_config(self, name, xml): logger.debug('upgrade task task "%s"', name) return self.jenkins[name].update_config(xml)
class BaseSystemTest(unittest.TestCase): def setUp(self): port = jenkinsapi_tests.systests.state['launcher'].http_port self.jenkins = Jenkins('http://localhost:%d' % port) self._delete_all_jobs() self._delete_all_views() def tearDown(self): pass def _delete_all_jobs(self): self.jenkins.poll() for name in self.jenkins.get_jobs_list(): self.jenkins.delete_job(name) def _delete_all_views(self): all_view_names = self.jenkins.views.keys()[1:] for name in all_view_names: del self.jenkins.views[name] def _create_job(self, name='whatever', config=EMPTY_JOB): job = self.jenkins.create_job(name, config) self.jenkins.poll() return job def assertJobIsPresent(self, name): self.jenkins.poll() self.assertTrue(name in self.jenkins, 'Job %r is absent in jenkins.' % name) def assertJobIsAbsent(self, name): self.jenkins.poll() self.assertTrue(name not in self.jenkins, 'Job %r is present in jenkins.' % name)
def delete_test_jobs(): ''' finalizer for this fixture that removes left-over test jobs from the live jenkins server. ''' jenkins = Jenkins(jenkins_url, jenkins_user, jenkins_pass) for job_name in jenkins.iterkeys(): if job_name.startswith(JOB_TEST_PREFIX): jenkins.delete_job(job_name)
def delete_test_jobs(): ''' finalizer for this fixture that removes left-over test jobs from the live jenkins server. ''' jenkins = Jenkins(JENKINS_URL) for name, job in jenkins.get_jobs(): if name.startswith(JOB_TEST_PREFIX): jenkins.delete_job(name)
def main(): # TODO: specify requirements and check inputs. module=AnsibleModule( argument_spec=dict( host=dict(), state=dict(), name=dict(), template=dict(), ) ) host = module.params['host'] state = module.params['state'] name = module.params['name'] template = module.params['template'] # TODO: try catch here J = Jenkins(host) # TODO: try catch here # TODO: how to handle paths? if (template): txt = open(template) job_config = txt.read() job_config_xml = etree.fromstring(job_config) # There are 4 possible outcomes: created, updated, deleted, nochange. if (state == 'present'): # If the desired state is present we must check if the job exists and then check if the job has changed. if (J.has_job(name)): # The job exists so we must compare the XMLs for changes and update if they don't match. current_conf = J[name].get_config() current_conf = current_conf.encode('ascii','replace') current_conf_xml = etree.fromstring(current_conf) if (xml_compare(job_config_xml, current_conf_xml)): module.exit_json(msg="job exists", changed=False) else: J[name].update_config(job_config) module.exit_json(msg="job updated", changed=True) else: new_job = J.create_job(name, job_config) module.exit_json(msg="job created", changed=True) elif (state == 'absent'): if (J.has_job(name)): J.delete_job(name) module.exit_json(msg="job deleted", changed=True) else: module.exit_json(msg="job does not exist", changed=False) module.exit_json(msg=J.version, changed=False)
def cit_rm(branch, global_config): cit_file_name, job_config = load_cit_local_config(os.getcwd()) if branch is None: branch = get_git_branch(cit_file_name) jenkins_url = global_config['jenkins']['url'] jenkins = Jenkins(jenkins_url) for _, new_job_name in get_configured_jobs(branch, job_config): if jenkins.has_job(new_job_name): jenkins.delete_job(new_job_name) print new_job_name, '(REMOVED)' else: print new_job_name, '(NOT FOUND)'
def main(): # TODO: specify requirements and check inputs. module = AnsibleModule(argument_spec=dict( host=dict(), state=dict(), name=dict(), template=dict(), )) host = module.params['host'] state = module.params['state'] name = module.params['name'] template = module.params['template'] # TODO: try catch here J = Jenkins(host) # TODO: try catch here # TODO: how to handle paths? if (template): txt = open(template) job_config = txt.read() job_config_xml = etree.fromstring(job_config) # There are 4 possible outcomes: created, updated, deleted, nochange. if (state == 'present'): # If the desired state is present we must check if the job exists and then check if the job has changed. if (J.has_job(name)): # The job exists so we must compare the XMLs for changes and update if they don't match. current_conf = J[name].get_config() current_conf = current_conf.encode('ascii', 'replace') current_conf_xml = etree.fromstring(current_conf) if (xml_compare(job_config_xml, current_conf_xml)): module.exit_json(msg="job exists", changed=False) else: J[name].update_config(job_config) module.exit_json(msg="job updated", changed=True) else: new_job = J.create_job(name, job_config) module.exit_json(msg="job created", changed=True) elif (state == 'absent'): if (J.has_job(name)): J.delete_job(name) module.exit_json(msg="job deleted", changed=True) else: module.exit_json(msg="job does not exist", changed=False) module.exit_json(msg=J.version, changed=False)
def feature_branch_rm(args, branch, global_config, job_config): ''' Remove jobs associated with the current git branch. This will remove one or more jobs from jenkins created previously with "feature_branch_add". If no branch is given the current one will be used. ''' if args: branch = args[0] jenkins_url = global_config['jenkins']['url'] jenkins = Jenkins(jenkins_url) for _, new_job_name in get_configured_jobs(branch, job_config): if jenkins.has_job(new_job_name): jenkins.delete_job(new_job_name) print new_job_name, '(REMOVED)' else: print new_job_name, '(NOT FOUND)'
if 'SubView' in top_view.views: logger.error('SubView was not deleted') else: logger.info('SubView has been deleted') # Another way of creating sub view # This way sub view will have jobs in it logger.info('Attempting to create view with jobs inside nested view') top_view.views['SubView'] = job_name if 'SubView' not in top_view.views: logger.error('View was not created') else: logger.info('View has been created') logger.info('Attempting to delete sub_view') del top_view.views['SubView'] if 'SubView' in top_view.views: logger.error('SubView was not deleted') else: logger.info('SubView has been deleted') logger.info('Attempting to delete top view') del jenkins.views['TopView'] if 'TopView' not in jenkins.views: logger.info('View has been deleted') else: logger.error('View was not deleted') # Delete job that we created jenkins.delete_job(job_name)
from __future__ import print_function import logging logging.basicConfig() from jenkinsapi.jenkins import Jenkins from pkg_resources import resource_string J = Jenkins('http://localhost:8080') jobName = 'foo_job2' xml = resource_string('examples', 'addjob.xml') print(xml) j = J.create_job(jobname=jobName, config=xml) j2 = J[jobName] print(j) # Delete job J.delete_job(jobName)
def teardown_module(module): jenkins = Jenkins(JENKINS_URL) for name, job in jenkins.get_jobs(): if name.startswith(JOB_TEST_PREFIX): jenkins.delete_job(name)
def server_upload_jobs(args, global_config, opts): ''' Uploads jobs found in a directory directly to jenkins. The jobs should be defined as with a "config.xml" file per job, while the directory containing the "config.xml" file will be used as the name of the job: source-dir /job-name1 /config.xml /job-name2 /config.xml Executing "cit server_upload_jobs source-dir" will upload "job-1" and "job-2" to jenkins, creating or updating them. ''' if not args: print >> sys.stderr, "error: Must pass a directory name" return 2 directory = args[0] if not os.path.exists(directory): print >> sys.stderr, 'error: Directory "%s" does not exist' % directory return 2 jenkins_url = global_config['jenkins']['url'] jenkins = Jenkins(jenkins_url) search_pattern = None local_jobs = [] for dir_name in glob.glob(directory + '/*'): # Ignore all files if not os.path.isdir(dir_name): continue job_info = JobInfo(dir_name) if job_info.config_filename is None: print 'Missing config.xml file from %r' % dir_name continue if opts.reindex: if search_pattern is None: search_pattern = job_info.SearchPattern() elif search_pattern != job_info.SearchPattern(): raise ValueError('Bad job names pattern: %r != %r' % (search_pattern, job_info.SearchPattern())) job_info.update = jenkins.has_job(job_info.name) local_jobs.append(job_info) rename_jobs = {} delete_jobs = [] if opts.reindex: remote_jobs = get_remote_job_infos(search_pattern, global_config, jenkins=jenkins) remote_basenames = dict((ji.BaseName(), ji) for ji in remote_jobs) for job_info in local_jobs: base_name = job_info.BaseName() remote_job = remote_basenames.pop(base_name, None) if remote_job is not None and remote_job.name != job_info.name: rename_jobs[job_info.name] = remote_job.name delete_jobs = [ji.name for ji in remote_basenames.itervalues()] for job_info in local_jobs: if job_info.name in rename_jobs: print 'Renaming %r -> %r' % (rename_jobs[job_info.name], job_info.name) elif job_info.update: print 'Updating %r' % job_info.name else: print 'Creating %r' % job_info.name for job_name in delete_jobs: print print 'Deleting %r' % job_name print if len(local_jobs) > 0: ans = raw_input('Update jobs (y|*n): ') if ans.startswith('y'): for job_info in local_jobs: config_xml = file(job_info.config_filename).read() if job_info.name in rename_jobs: remote_name = rename_jobs[job_info.name] print '\tUpdating job' job = jenkins.get_job(remote_job.name) job.update_config(config_xml) print 'Renaming %r -> %r' % (remote_name, job_info.name) jenkins.rename_job(remote_name, job_info.name) else: if job_info.update: print 'Updating %r' % job_info.name job = jenkins.get_job(job_info.name) job.update_config(config_xml) else: print 'Creating %r' % job_info.name job = jenkins.create_job(job_info.name, config_xml) for job_name in delete_jobs: print 'Deleting %r' % job_name job = jenkins.delete_job(job_name)
if 'SubView' in top_view.views: logger.error('SubView was not deleted') else: logger.info('SubView has been deleted') # Another way of creating sub view # This way sub view will have jobs in it logger.info('Attempting to create view with jobs inside nested view') top_view.views['SubView'] = jobName if 'SubView' not in top_view.views: logger.error('View was not created') else: logger.info('View has been created') logger.info('Attempting to delete sub_view') del top_view.views['SubView'] if 'SubView' in top_view.views: logger.error('SubView was not deleted') else: logger.info('SubView has been deleted') logger.info('Attempting to delete top view') del api.views['TopView'] if 'TopView' not in api.views: logger.info('View has been deleted') else: logger.error('View was not deleted') # Delete job that we created api.delete_job(jobName)
class JenkinsCI: def __init__(self, jenkins_url, username, password): self.jenkins_url = jenkins_url self.jenkins = Jenkins(self.jenkins_url, username=username, password=password) self.build_info = [] __user_data = "Basic " + (username + ":" + password).encode("base64").rstrip() self.__headers = {"Content-Type": "application/x-www-form-urlencoded", "Authorization": __user_data} def __invoke_method(self, command, method="GET", parameters=None, silent=False): if parameters is None: parameters = {} method_url = urljoin(self.jenkins_url, command) request_data = None if method == "GET": query_string = urlencode(parameters) method_url = method_url + "?" + query_string else: request_data = urlencode(parameters) req = Request(method_url, data=request_data, headers=self.__headers) req.get_method = lambda: method try: response = urlopen(req).read() except HTTPError as e: if not silent: print "{0} : {1}".format(method_url, e) return None try: return loads(response.decode("utf-8")) except ValueError: return response.decode("utf-8") def create_job(self, job_name, xml_config): try: self.jenkins.create_job(job_name, xml_config) except Exception as e: print e return False else: print "[+] : job {0} created".format(job_name) return True def format_path_folder(self, path_folder): return "job/" + path_folder.replace("/", "/job/") def rename_folder(self, path_folder, new_path_folder): new_folder_name = new_path_folder.split("/")[-1] command = "{0}/doRename".format(self.format_path_folder(path_folder)) json_parameters = dumps({"newName": new_folder_name}) parameters = {"newName": new_folder_name, "Submit": "Yes", "json": json_parameters} result = self.__invoke_method(command, "POST", parameters) if not result: raise JenkinsException("Cannot rename folder {0} to {1}".format(path_folder, new_path_folder), 1) print "[+] : folder {0} renamed to {1}".format(path_folder, new_path_folder) def create_folder(self, path_folder, recursive=False): if recursive: return self.recursive_create_folders(path_folder) split_path = path_folder.split("/") folder_name = split_path[-1] command = "createItem" if len(split_path) > 1: new_path = "/".join(f for f in split_path[:-1]) command = self.format_path_folder(new_path) + "/" + command json_parameters = dumps({"name": folder_name, "mode": "com.cloudbees.hudson.plugins.folder.Folder", "from": "", "Submit": "OK"}) parameters = {"name": folder_name, "mode": "com.cloudbees.hudson.plugins.folder.Folder", "from": "", "Submit": "OK", "json": json_parameters} result = self.__invoke_method(command, "GET", parameters) if not result: raise JenkinsException("Cannot create folder {0}".format(path_folder), 1) print "[+] : folder {0} created".format(path_folder) def recursive_create_folders(self, path_folder): split_path = path_folder.split("/") root = split_path[0] for folder in split_path[1:]: if not self.check_folder_exist(root): self.create_folder(root) root += "/{0}".format(folder) def check_folder_exist(self, path_folder): result = self.__invoke_method(self.format_path_folder(path_folder), "GET", silent=True) if result: return True return False def move_job_on_folder(self, job_name, path_folder): command = "{0}/move/move".format(self.format_path_folder(job_name)) json_parameters = {"destination": "/{0}".format(path_folder)} parameters = {"destination": "/{0}".format(path_folder), "json": json_parameters, "Submit": "Move"} result = self.__invoke_method(command, "POST", parameters) if not result: raise JenkinsException("Cannot move job {0} to {1} folder".format(job_name, path_folder), 2) print "[+] : Job {0} moved to {1} folder".format(job_name, path_folder) def get_plugins_version_dict(self, plugins_name_list): plugins_version_dict = {} all_plugins = self.jenkins.get_plugins().get_plugins_dict() for plugin in plugins_name_list: plugins_version_dict[plugin] = all_plugins[plugin].version return plugins_version_dict def copy_job(self, template_job, new_job): try: self.jenkins.copy_job(template_job, new_job) except Exception as e: print e return False else: print "[+] : Job {0} created".format(new_job) return True def plugins_checker(self, plugins_list): all_installed = True for plugin in plugins_list: if not self.jenkins.has_plugin(plugin): all_installed = False print "[-] : Plugin {0} is not installed".format(plugin) if not all_installed: return False return True def check_job_exist(self, job_name): if self.jenkins.has_job(job_name): return True return False def check_jobs_exist(self, jobs_list): status_exist = False for job in jobs_list: if self.check_job_exist(job): print "[-] : Job {0} already exist".format(job) status_exist = True return status_exist def create_view(self, view_name): views = self.jenkins.views if view_name not in views.keys(): views.create(view_name) print "[+] : view {0} created".format(view_name) def move_job_on_view(self, view_name, job_name): view_url = "{0}/view/{1}".format(self.jenkins_url, view_name) view = self.jenkins.get_view_by_url(view_url) view.add_job(job_name) def delete_job(self, job_name): if self.check_job_exist(job_name): self.jenkins.delete_job(job_name) print "[+] : job {0} deleted".format(job_name) def build_job(self, job_name, arguments): job = self.jenkins.get_job(job_name) build_number = job.get_next_build_number() job.invoke(build_params=arguments) return build_number def get_git_info_build(self, job_name, build_number): job = self.jenkins.get_job(job_name) build = job.get_build(build_number) return build.get_revision() def get_url_build(self, job_name, build_number): return "{0}/job/{1}/{2}".format(self.jenkins_url, job_name, build_number) def print_info_build(self, job_name, build_number): url = self.get_url_build(job_name, build_number) git_info = self.get_git_info_build(job_name, build_number) print "Job: {0} #{1}".format(job_name, build_number) print "Url: {0}".format(url) for info in git_info: print "Branch : {0} | Revision : {1}".format(info["name"], info["SHA1"])
# This is to test jenkins capability to handle a large number of # jobs. (e.g. 100000) # requires the jenkinsapi egg: # https://github.com/salimfadhley/jenkinsapi import time from jenkinsapi.jenkins import Jenkins limit = 100000 j = Jenkins('http://localhost:8080') text_buffer = None with open('test.xml') as fh: text_buffer = fh.read() print "Deleting jobs..." for i in range(limit): try: j.delete_job('job-%d' % i) except Exception: pass print "deleted!" start_time = time.time() for i in range(limit): print "Creating job #%d..." % i j.create_job('job-%d' % i, text_buffer) print "Success!" end_time = time.time() print "Elapsed time: %f" % (end_time - start_time)
import sys import jenkinsapi from jenkinsapi import * from jenkinsapi.jenkins import Jenkins if len(sys.argv) >= 2: Job_To_Be_Deleted = sys.argv[1] else: raise Exception("Either No Job Supplied or Job does not Exist") Jenkins_Server = Jenkins("http://localhost:8080") # This will give you the list of all jobs in Jenkins Jobs = Jenkins_Server.keys() print "\n Printing all the Jobs in Jenkins \n" for job in range(len(Jobs)): print Jobs[job] if Jenkins_Server.has_job(Job_To_Be_Deleted) is True: print "" print "The Following Job will be deleted" print Job_To_Be_Deleted else: print "Either No Job Supplied or Job does not Exist" raise Exception("Either No Job Supplied or Job does not Exist") # This command will delete a job from Jenkins Jenkins_Server.delete_job(Job_To_Be_Deleted)
class JenkinsWorks: """ Wrapper class that provides connection with Jenkins """ def __init__(self, url, username, password, repository_path, template_location, template_name, job_prefix, job_suffix, view_prefix, view_suffix, preview): """ JenkinsWorks constructor. Sets necessary variables """ self.jenkins_url = url self.jenkins_username = username self.jenkins_password = password self.repo_path = repository_path self.template_name = template_name self.job_prefix = job_prefix self.job_suffix = job_suffix self.view_prefix = view_prefix self.view_suffix = view_suffix self.preview = preview self.existing_jobs = [] self.existing_views = [] self.branches = [] self._get_api_instance() self._get_repo_origin() def _get_api_instance(self): """ Get Jenkins API object """ self.api = Jenkins(self.jenkins_url, self.jenkins_username, self.jenkins_password) return self.api def _get_repo_origin(self): """ Get Git origin url """ self.repo = git.Repo(self.repo_path) self.repo_url = self.repo.remotes.origin.url return self.repo_url def get_existing_jobs_list(self): """ Get existing Jenkins job names that conform to the following convention: prefix + branch_name + suffix """ for job in self.api.get_jobs(): job_instance = self.api.get_job(job[0]) if re.match(self.job_prefix + ".*" + self.job_suffix, job_instance.name): self.existing_jobs.append(job_instance.name) return self.existing_jobs def get_existing_views(self): """ Get existing Jenkins views that conform to the following convention: prefix + branch_name + suffix """ for view_name in self.api.views.keys(): if re.match(self.view_prefix + ".*" + self.view_suffix, view_name): self.existing_views.append(view_name) return self.existing_views def get_branches(self): """ Get all remote branches from Git """ pattern = re.compile('[\w\d]+\trefs/heads/(.*)') output = self.repo.git.ls_remote("--heads").split("\n") for line in output: result = pattern.match(line) if result: self.branches.append(result.group(1)) return self.branches def render_template(self, branch): """ Render XML from the Jinja2 template """ from jinja import FileSystemLoader from jinja.environment import Environment env = Environment() env.loader = FileSystemLoader('templates') template = env.get_template(self.template_name) rendered_xml = template.render(git_repo=self.repo_url, git_branch=branch) return rendered_xml def create_job(self, job_name, xml): """ Create Jenkins job with specific job name and rendered from Jinja2 template XML """ print("Creating job: %s" % job_name) if not self.preview: self.api.create_job(jobname=job_name, xml=xml) def delete_job(self, job_name): """ Delete Jenkins job """ print("Deleting job: %s" % job_name) if not self.preview: self.api.delete_job(jobname=job_name) def create_view(self, view_name): """ Create Jenkins view with specific view name """ print("Creating view: %s" % view_name) if not self.preview: view = self.api.views.create(view_name) return view return view_name def populate_view(self, view, job_name): """ Add job to the Jenkins view """ print("Adding job %s to view %s" % (job_name, view.__str__())) if not self.preview: view.add_job(job_name) def delete_view(self, view_name): """ Delete Jenkins view """ print("Deleting view: %s" % view_name) if not self.preview: del self.api.views[view_name] def update_jenkins_config(self): """ Function that decides what Jenkins jobs and views should be created and what should be deleted """ if self.preview: print("Going to run in the PREVIEW mode") created_jobs = [] created_views = [] for branch in self.branches: job_name = self.job_prefix + branch + self.job_suffix view_name = self.view_prefix + branch if job_name not in self.existing_jobs: xml = self.render_template(branch) self.create_job(job_name, xml) if view_name not in self.existing_views: view = self.create_view(view_name) self.populate_view(view, job_name) created_jobs.append(job_name) created_views.append(view_name) for job in self.existing_jobs: if job not in created_jobs: self.delete_job(job) for view in self.existing_views: if view not in created_views: self.delete_view(view)
from __future__ import print_function from pkg_resources import resource_string from jenkinsapi.jenkins import Jenkins from jenkinsapi.utils.crumb_requester import CrumbRequester url = "url" username = "******" password = "******" crumb_requester = CrumbRequester(baseurl=url, username=username, password=password) j = Jenkins(url, username=username, password=password, requester=crumb_requester) job_name = 'jobName' job = j.delete_job(jobname=job_name) print ("Job", job_name, "deleted")
def cit_up_from_dir(directory, global_config, reindex=True): jenkins_url = global_config['jenkins']['url'] jenkins = Jenkins(jenkins_url) directory = directory or 'hudson' if not os.path.exists(directory): print 'Directory not found: %r' % directory return search_pattern = None local_jobs = [] for dir_name in glob.glob(directory + '/*'): # Ignore all files if not os.path.isdir(dir_name): continue job_info = JobInfo(dir_name) if job_info.config_filename is None: print 'Missing config.xml file from %r' % dir_name continue if reindex: if search_pattern is None: search_pattern = job_info.SearchPattern() elif search_pattern != job_info.SearchPattern(): raise ValueError('Bad job names pattern: %r != %r' % (search_pattern, job_info.SearchPattern())) job_info.update = jenkins.has_job(job_info.name) local_jobs.append(job_info) rename_jobs = {} delete_jobs = [] if reindex: remote_jobs = GetRemoteJobInfos(search_pattern, global_config, jenkins=jenkins) remote_basenames = dict((ji.BaseName(), ji) for ji in remote_jobs) for job_info in local_jobs: base_name = job_info.BaseName() remote_job = remote_basenames.pop(base_name, None) if remote_job is not None and remote_job.name != job_info.name: rename_jobs[job_info.name] = remote_job.name delete_jobs = [ji.name for ji in remote_basenames.itervalues()] for job_info in local_jobs: if job_info.name in rename_jobs: print 'Renaming %r -> %r' % (rename_jobs[job_info.name], job_info.name) elif job_info.update: print 'Updating %r' % job_info.name else: print 'Creating %r' % job_info.name for job_name in delete_jobs: print print 'Deleting %r' % job_name print if len(local_jobs) > 0: ans = raw_input('Update jobs (y|*n): ') if ans.startswith('y'): for job_info in local_jobs: config_xml = file(job_info.config_filename).read() if job_info.name in rename_jobs: remote_name = rename_jobs[job_info.name] print '\tUpdating job' job = jenkins.get_job(remote_job.name) job.update_config(config_xml) print 'Renaming %r -> %r' % (remote_name, job_info.name) jenkins.rename_job(remote_name, job_info.name) else: if job_info.update: print 'Updating %r' % job_info.name job = jenkins.get_job(job_info.name) job.update_config(config_xml) else: print 'Creating %r' % job_info.name job = jenkins.create_job(job_info.name, config_xml) for job_name in delete_jobs: print 'Deleting %r' % job_name job = jenkins.delete_job(job_name)