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 copy
import itertools
import fnmatch
from jenkins_jobs.errors import JenkinsJobsException
logger = logging.getLogger(__name__)
@ -61,6 +62,19 @@ def deep_format(obj, paramdict):
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):
def __init__(self, config=None):
self.registry = ModuleRegistry(config)
@ -120,7 +134,8 @@ class YamlParser(object):
changed = True
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
logger.debug("XMLifying job '{0}'".format(job['name']))
job = self.applyDefaults(job)
@ -205,7 +220,7 @@ class YamlParser(object):
# We also want to skip XML generation whenever the user did
# not ask for that job.
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
logger.debug("Generating XML for template job {0}"
@ -432,10 +447,17 @@ class Builder(object):
self.global_config = config
self.ignore_cache = ignore_cache
def delete_job(self, name):
self.jenkins.delete_job(name)
if(self.cache.is_cached(name)):
self.cache.set(name, '')
def load_files(self, fn):
if os.path.isdir(fn):
files_to_process = [os.path.join(fn, f)
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):
jobs = self.jenkins.get_jobs()
@ -446,30 +468,33 @@ class Builder(object):
.format(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):
jobs = self.jenkins.get_jobs()
for job in jobs:
self.delete_job(job['name'])
def update_job(self, fn, names=None, output_dir=None):
if os.path.isdir(fn):
files_to_process = [os.path.join(fn, f)
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)
self.load_files(fn)
self.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:
if names and job.name not in names:
for job in self.parser.jobs:
if names and not matches(job.name, names):
continue
if output_dir:
if names:
@ -492,4 +517,4 @@ class Builder(object):
self.cache.set(job.name, md5)
else:
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_delete = subparser.add_parser('delete')
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',
help='Delete *ALL* jobs from Jenkins server, '
'including those not managed by Jenkins Job '
@ -99,8 +101,8 @@ def main():
if options.command == 'delete':
for job in options.name:
logger.info("Deleting job {0}".format(job))
builder.delete_job(job)
logger.info("Deleting jobs in [{0}]".format(job))
builder.delete_job(job, options.path)
elif options.command == 'delete-all':
confirm('Sure you want to delete *ALL* jobs from Jenkins server?\n'
'(including those not managed by Jenkins Job Builder)')