Added globbed parameters to the job specification

Now you can specify a globbed parameter when updating or deleting a job,
it will parse the yaml files and select those jobs that match to be
updated/deleted

For example:
  jenkins-jobs --config ~/jenkins.ini update myjobs/ \*only_those\*

Will only update the jobs that have 'only_those' on their name.

For the delete subcommand the option '-p' lets you specify the path
where to load the job list from, so you can use globs for the jobs in
that list (it does not allow you to use globs with non-managed jobs)

Change-Id: I5bb1074845fb143c7c3120c138a6b138d3548305
Signed-off-by: David Caro <dcaroest@redhat.com>
This commit is contained in:
David Caro 2013-08-07 18:55:13 +02:00
parent 72d32db155
commit 4dd267ee0d
2 changed files with 52 additions and 25 deletions

View File

@ -27,6 +27,7 @@ import pkg_resources
import logging import logging
import copy import copy
import itertools import itertools
import fnmatch
from jenkins_jobs.errors import JenkinsJobsException from jenkins_jobs.errors import JenkinsJobsException
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -61,6 +62,19 @@ def deep_format(obj, paramdict):
return ret return ret
def matches(what, where):
"""
Checks if the given string matches against the given list of glob patterns
:arg str what: String that we want to test if matches
:arg list where: list of glob patters to match
"""
for pattern in where:
if re.match(fnmatch.translate(pattern), what):
return True
return False
class YamlParser(object): class YamlParser(object):
def __init__(self, config=None): def __init__(self, config=None):
self.registry = ModuleRegistry(config) self.registry = ModuleRegistry(config)
@ -120,7 +134,8 @@ class YamlParser(object):
changed = True changed = True
for job in self.data.get('job', {}).values(): for job in self.data.get('job', {}).values():
if jobs_filter and job['name'] not in jobs_filter: if jobs_filter and not matches(job['name'], jobs_filter):
logger.debug("Ignoring job {}".format(job['name']))
continue continue
logger.debug("XMLifying job '{0}'".format(job['name'])) logger.debug("XMLifying job '{0}'".format(job['name']))
job = self.applyDefaults(job) job = self.applyDefaults(job)
@ -205,7 +220,7 @@ class YamlParser(object):
# We also want to skip XML generation whenever the user did # We also want to skip XML generation whenever the user did
# not ask for that job. # not ask for that job.
job_name = expanded.get('name') job_name = expanded.get('name')
if jobs_filter and job_name not in jobs_filter: if jobs_filter and not matches(job_name, jobs_filter):
continue continue
logger.debug("Generating XML for template job {0}" logger.debug("Generating XML for template job {0}"
@ -432,10 +447,17 @@ class Builder(object):
self.global_config = config self.global_config = config
self.ignore_cache = ignore_cache self.ignore_cache = ignore_cache
def delete_job(self, name): def load_files(self, fn):
self.jenkins.delete_job(name) if os.path.isdir(fn):
if(self.cache.is_cached(name)): files_to_process = [os.path.join(fn, f)
self.cache.set(name, '') for f in os.listdir(fn)
if (f.endswith('.yml') or f.endswith('.yaml'))]
else:
files_to_process = [fn]
self.parser = YamlParser(self.global_config)
for in_file in files_to_process:
logger.debug("Parsing YAML file {0}".format(in_file))
self.parser.parse(in_file)
def delete_old_managed(self, keep): def delete_old_managed(self, keep):
jobs = self.jenkins.get_jobs() jobs = self.jenkins.get_jobs()
@ -446,30 +468,33 @@ class Builder(object):
.format(job['name'])) .format(job['name']))
self.delete_job(job['name']) self.delete_job(job['name'])
def delete_job(self, glob_name, fn=None):
if fn:
self.load_files(fn)
self.parser.generateXML(glob_name)
jobs = [j.name
for j in self.parser.jobs
if matches(j.name, [glob_name])]
else:
jobs = [glob_name]
for job in jobs:
self.jenkins.delete_job(job)
if(self.cache.is_cached(job)):
self.cache.set(job, '')
def delete_all_jobs(self): def delete_all_jobs(self):
jobs = self.jenkins.get_jobs() jobs = self.jenkins.get_jobs()
for job in jobs: for job in jobs:
self.delete_job(job['name']) self.delete_job(job['name'])
def update_job(self, fn, names=None, output_dir=None): def update_job(self, fn, names=None, output_dir=None):
if os.path.isdir(fn): self.load_files(fn)
files_to_process = [os.path.join(fn, f) self.parser.generateXML(names)
for f in os.listdir(fn)
if (f.endswith('.yml') or f.endswith('.yaml'))]
else:
files_to_process = [fn]
parser = YamlParser(self.global_config)
for in_file in files_to_process:
logger.debug("Parsing YAML file {0}".format(in_file))
parser.parse(in_file)
if names:
logger.debug("Will filter out jobs not in %s" % names)
parser.generateXML(names)
parser.jobs.sort(lambda a, b: cmp(a.name, b.name)) self.parser.jobs.sort(lambda a, b: cmp(a.name, b.name))
for job in parser.jobs: for job in self.parser.jobs:
if names and job.name not in names: if names and not matches(job.name, names):
continue continue
if output_dir: if output_dir:
if names: if names:
@ -492,4 +517,4 @@ class Builder(object):
self.cache.set(job.name, md5) self.cache.set(job.name, md5)
else: else:
logger.debug("'{0}' has not changed".format(job.name)) logger.debug("'{0}' has not changed".format(job.name))
return parser.jobs return self.parser.jobs

View File

@ -45,6 +45,8 @@ def main():
parser_test.add_argument('name', help='name(s) of job(s)', nargs='*') parser_test.add_argument('name', help='name(s) of job(s)', nargs='*')
parser_delete = subparser.add_parser('delete') parser_delete = subparser.add_parser('delete')
parser_delete.add_argument('name', help='name of job', nargs='+') parser_delete.add_argument('name', help='name of job', nargs='+')
parser_delete.add_argument('-p', '--path', default=None,
help='Path to YAML file or directory')
subparser.add_parser('delete-all', subparser.add_parser('delete-all',
help='Delete *ALL* jobs from Jenkins server, ' help='Delete *ALL* jobs from Jenkins server, '
'including those not managed by Jenkins Job ' 'including those not managed by Jenkins Job '
@ -99,8 +101,8 @@ def main():
if options.command == 'delete': if options.command == 'delete':
for job in options.name: for job in options.name:
logger.info("Deleting job {0}".format(job)) logger.info("Deleting jobs in [{0}]".format(job))
builder.delete_job(job) builder.delete_job(job, options.path)
elif options.command == 'delete-all': elif options.command == 'delete-all':
confirm('Sure you want to delete *ALL* jobs from Jenkins server?\n' confirm('Sure you want to delete *ALL* jobs from Jenkins server?\n'
'(including those not managed by Jenkins Job Builder)') '(including those not managed by Jenkins Job Builder)')