diff --git a/jenkins_jobs/builder.py b/jenkins_jobs/builder.py index d3dea174a..b7de312a8 100644 --- a/jenkins_jobs/builder.py +++ b/jenkins_jobs/builder.py @@ -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 diff --git a/jenkins_jobs/cmd.py b/jenkins_jobs/cmd.py index 03780b560..546da86fc 100755 --- a/jenkins_jobs/cmd.py +++ b/jenkins_jobs/cmd.py @@ -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)')