def getStatus(): rid = request.args.get("rid") JS_URL = app.config["JENKINS_URL"] app.logger.debug('Connecting to Jenkins %s as %s', JS_URL, app.config["UID"]) js = JenkinsServer(JS_URL, username=app.config["UID"], password=app.config["PWD"]) app.logger.debug('Connected') app.logger.info('Hello from Jenkins %s', js.get_version()) allBuilds = js.get_job_info(app.config["FOLDER_NAME"] + '/' + app.config["PIPELINE_NAME"], fetch_all_builds=True) ret = "{" for build in allBuilds['builds']: bi = js.get_build_info( app.config["FOLDER_NAME"] + '/' + app.config["PIPELINE_NAME"], build['number']) if (bi['displayName'] == rid): ret += " \"displayName\": \"" + str(bi['displayName']) + "\", " ret += " \"buildNumber\": \"" + str(build['number']) + "\", " ret += " \"building\": \"" + str(bi['building']) + "\", " ret += " \"result\": \"" + str(bi['result']) + "\"" continue ret += "}" return ret
def main(build_url, sleeptime=15, pushover=False): if pushover and not have_pushover: raise SystemExit("ERROR: to use pushover notifications, please `pip install python-pushover` and configure it.") job_name, build_no = get_job_name_and_build_number(build_url) jenkins_url = get_jenkins_base_url(build_url) logger.debug("Connecting to Jenkins...") """ NOTE: this is using unauthenticated / anonymous access. If that doesn't work for you, change this to something like: j = Jenkins(jenkins_url, 'username', 'password') """ j = Jenkins(jenkins_url) logger.debug("Connected.") if build_no is None: jobinfo = j.get_job_info(job_name) build_no = jobinfo['nextBuildNumber'] - 1 print("Using latest build, #{b}".format(b=build_no)) build_url = get_formal_build_url(jenkins_url, job_name, build_no) print("Watching job {j} #{b} until completion <{u}>...".format(j=job_name, b=build_no, u=build_url)) while True: buildinfo = j.get_build_info(job_name, build_no) if not buildinfo['building']: # job is not still building duration = datetime.timedelta(seconds=(buildinfo['duration'] / 1000)) if pushover: notify_pushover(buildinfo['result'], job_name, build_no, duration, build_url) if buildinfo['result'] == "SUCCESS": print("SUCCESS for {j} #{b} in {d} <{bu}>".format(j=job_name, b=build_no, bu=build_url, d=duration)) raise SystemExit(0) print("{r}: {j} #{b} failed in {d}".format(j=job_name, b=build_no, r=buildinfo['result'], d=duration)) raise SystemExit(1) else: duration = datetime.datetime.now() - datetime.datetime.fromtimestamp(buildinfo['timestamp'] / 1000) print("still running ({d})...".format(d=duration)) time.sleep(sleeptime)
class JenkinsInfo: config = Config.get_jenkins_config() def __init__(self): self.jks = Jenkins(url=self.config["url"], username=self.config["user"], password=self.config["pwd"]) self.job_name = self.config["job_name"] def get_info(self): result = dict() last_success_info = self.jks.get_job_info(self.job_name)["lastSuccessfulBuild"] url = last_success_info["url"] last_num = last_success_info["number"] # result["last_num"] = last_num build_info = self.jks.get_build_info(self.job_name, last_num) artifact = build_info["artifacts"][0] apk_name = artifact["fileName"] result["apk_name"] = apk_name relative_path = artifact["relativePath"] download_url = f"{url}artifact/{relative_path}" result["download_url"] = download_url return result
def _upsert_jenkins_job(server: Jenkins, full_job_name: str, xml_job_config: str): if server.job_exists(full_job_name): job = server.get_job_info(full_job_name) else: print(f'Jenkins job {full_job_name} doesn''t exist.') job = None config_xml_string = canonicalize_jenkins_xml(xml_job_config) if job is None and writeback: print(f'Creating new job {full_job_name}') try: server.create_job(full_job_name, config_xml_string) except JenkinsException as e: print(f'Failed creating job:\n{e}') elif job is not None: current_xml_string = canonicalize_jenkins_xml(server.get_job_config(full_job_name)) diffs = diff_files(BytesIO(bytearray(current_xml_string, encoding='utf-8')), BytesIO(bytearray(config_xml_string, encoding='utf-8'))) if len(diffs) > 0: print(f'Jenkins job {full_job_name} needs update') if writeback: print(json.dumps(diffs, indent=4)) if input(f'Are you sure you want to update configuration for {full_job_name} (y/n) ? ') == 'y': print(f'Updating job configuration for {full_job_name}') try: server.reconfig_job(full_job_name, config_xml_string) except JenkinsException as e: print(f'Failed updating job:\n{e}')
class TaskBuilder: def __init__(self, jenkinsURL): self.j = Jenkins(jenkinsURL) self.jobName = "" #with open("config.xml") as file: with open("./builds/config/job/config.xml") as file: self.templateConfig = file.read() self.template = Template(unicode(self.templateConfig)) def set_new_config(self, **params): self.newConfig = self.template.render(repos=params['repos'], description=params['repos']) def add_build(self, **params): self.set_job_name(**params) self.set_new_config(**params) if self.j.job_exists(self.jobName): self.do_build(**params) else: self.j.create_job(self.jobName, self.newConfig) self.do_build(**params) def do_build(self, **params): self.set_job_name(**params) self.set_new_config(**params) self.j.enable_job(self.jobName) self.j.build_job(self.jobName, {'branch': params['branch'], 'version': params['version'], 'author': params['author'], \ 'styleguide_repo': params['styleguide_repo'], 'styleguide_branch': params['styleguide_branch'], 'sidecar_repo': params['sidecar_repo'], \ 'sidecar_branch': params['sidecar_branch'], 'package_list': params['package_list'], 'upgrade_package': params['upgrade_package']}) def set_job_name(self,**params): buildUtil = BuildUtil() self.jobName = buildUtil.get_job_name(repos=params['repos']) def get_build_status(self, jobName): #job_info = self.j.get_job_info(self.jobName) #return build_status color_status = {"aborted":"Aborted", "red": "Failed", "blue": "Succcess"} if jobName == "": print "Have to specify job name" return False else: if self.j.job_exists(jobName): #Job exist in the job list job_info = self.j.get_job_info(jobName) if color_status.has_key(job_info['color']): return color_status[job_info['color']] else: return 'Running' else: print "Have to specify a validate job name" return False def get_job_name(self): return self.jobName
class JenkinsAPI(object): def __init__(self): self.__server = Jenkins(settings.JENKINS.get('URI')) def get_all_jobs(self): return self.__server.get_all_jobs() def get_next_build_number(self, name): return self.__server.get_job_info(name)['nextBuildNumber'] def build_job(self, name, parameters=None): return self.__server.build_job(name=name, parameters=parameters) def get_build_info(self, name, build_number): try: return self.__server.get_build_info(name, build_number) except Exception as e: logger.exception(e) return None def get_build_console_output(self, name, number): try: return self.__server.get_build_console_output(name, number) except JenkinsException as e: logger.exception(e) return None def download_package(self, package_url, name, build_number): URI = settings.JENKINS.get('URI') download_url = '{}/job/{}/{}/artifact/{}'.format( URI, name, build_number, package_url) logger.debug(download_url) local_filename = download_url.split('/')[-1] code_path = os.path.join(settings.DEPLOY.get('CODE_PATH'), 'packages') local_full_filename = os.path.join(code_path, local_filename) # with requests.get(url, stream=True, # auth=HTTPBasicAuth("zhoujinliang", "117c911a35acf51e428e29f3ccb363f53f")) as r: with requests.get(download_url, stream=True) as r: r.raise_for_status() with open(local_full_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=8192): if chunk: # filter out keep-alive new chunks f.write(chunk) return local_full_filename def cancel_build(self, name, queue_id, build_number): try: self.__server.cancel_queue(queue_id) self.__server.stop_build(name, build_number) except Exception as e: logger.error(e) def test(self): return self.__server.cancel_queue(3590) # # return self.__server.stop_build('devops', 98) return self.__server.get_queue_info()
def main(build_url, sleeptime=15, pushover=False, user=None, password=None): if pushover and not have_pushover: raise SystemExit( "ERROR: to use pushover notifications, please `pip install python-pushover` and configure it." ) job_name, build_no = get_job_name_and_build_number(build_url) logger.info("Job: %s", job_name) logger.info("Build Number: %s", build_no) jenkins_url = get_jenkins_base_url(build_url) logger.debug("Connecting to Jenkins...") if user is not None: logger.debug("Connecting to Jenkins as user %s ...", user) j = Jenkins(jenkins_url, user, password) else: logger.debug("Connecting to Jenkins anonymously...") j = Jenkins(jenkins_url) logger.debug("Connected.") if build_no is None: jobinfo = j.get_job_info(job_name) build_no = jobinfo['nextBuildNumber'] - 1 logger.info("Using latest build, #{b}".format(b=build_no)) build_url = get_formal_build_url(jenkins_url, job_name, build_no) print("Watching job {j} #{b} until completion <{u}>...".format( j=job_name, b=build_no, u=build_url)) while True: logger.debug("Getting build info...") buildinfo = j.get_build_info(job_name, build_no) if not buildinfo['building']: # job is not still building duration = datetime.timedelta(seconds=(buildinfo['duration'] / 1000)) if pushover: notify_pushover(buildinfo['result'], job_name, build_no, duration, build_url) if buildinfo['result'] == "SUCCESS": print("SUCCESS for {j} #{b} in {d} <{bu}>".format(j=job_name, b=build_no, bu=build_url, d=duration)) raise SystemExit(0) print("{r}: {j} #{b} failed in {d}".format(j=job_name, b=build_no, r=buildinfo['result'], d=duration)) raise SystemExit(1) else: duration = datetime.datetime.now( ) - datetime.datetime.fromtimestamp(buildinfo['timestamp'] / 1000) print("still running ({d})...".format(d=duration)) time.sleep(sleeptime)
class JenkinsBot(BotPlugin): def __init__(self): self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD) @botcmd def jenkins_list(self, mess, args): """List all jobs, optionally filter them using a search term.""" self.send(mess.getFrom(), u'/me is getting the list of jobs from Jenkins... ', message_type=mess.getType()) search_term = args.strip().lower() jobs = [ job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower() ] return self.format_jobs(jobs) @botcmd def jenkins_running(self, mess, args): """List all running jobs.""" self.send(mess.getFrom(), u'/me is getting the list of jobs from Jenkins... ', message_type=mess.getType()) jobs = [ job for job in self.jenkins.get_jobs() if 'anime' in job['color'] ] return self.format_running_jobs(jobs) def format_jobs(self, jobs): if len(jobs) == 0: return u'No jobs found.' max_length = max([len(job['name']) for job in jobs]) return '\n'.join([ '%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs ]).strip() def format_running_jobs(self, jobs): if len(jobs) == 0: return u'No running jobs.' jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs] return '\n\n'.join([ '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info ]).strip()
def errors(job_name, jenkins_username, jenkins_token): """Console script for jenkins_triage.""" global server # job_name = 'enterprise_pe-acceptance-tests_integration-system_pe_full-upgrade_weekend_2016.4.x' # 'enterprise_pe-orchestrator_intn-van-sys-pez-multi_2016.4.x-2016.4.x' # 'enterprise_pe-modules-vanagon-suite_intn-van-sys-pez-multi_daily-pe-modules-2016.4.x' server = Jenkins( 'https://cinext-jenkinsmaster-enterprise-prod-1.delivery.puppetlabs.net', username=jenkins_username, password=jenkins_token) info = server.get_job_info(job_name) builds = [ server.get_build_info(job_name, build['number']) for build in info['builds'] ] failed_build_numbers = [b for b in builds if b['result'] == 'FAILURE'] last_job_errors = None counts = defaultdict(int) similar = set() for build in failed_build_numbers: output = server.get_build_console_output(job_name, build['number']) finder = get_strategy(output) errors = finder(output) print "Errors: {}".format(errors) if last_job_errors: seq = difflib.SequenceMatcher(a=last_job_errors, b=errors) if seq.ratio() == 1.0: counts['exact'] += 1 if seq.ratio() >= 0.7 and seq.ratio() < 1.0: counts['similar'] += 1 similar.append(errors) else: last_job_errors = errors if last_job_errors: click.echo('Last job errors were:') click.echo('\t{}'.format('\n\t'.join(last_job_errors))) if last_job_errors and 'exact' in counts: click.echo( 'There were {} jobs that failed with errors exactly the same as the last failed job:' .format(counts['exact'])) click.echo('\t{}'.format('\n\t'.join(last_job_errors))) if last_job_errors and 'similar' in counts: click.echo( 'There were {} jobs that failed with experienced similar errors as the last failed job:' .format(counts['exact'])) click.echo('\t{}'.format('\n\t'.join(last_job_errors))) for s in similar: click.echo('Additional Failed Job:') click.echo('\t{}'.format('\n\t'.join(s)))
def main(): parser = ArgumentParser() parser.add_argument('-j', '--jobname', type=str, default=None) parser.add_argument('-n', '--dry_run', action='store_true') parser.add_argument('-d', '--distro', type=str, default='all') # maybe implement an 'all' logic? parser.add_argument('-r', '--release', type=str, default='leste') args = parser.parse_args() if args.release not in DEFAULT_RELEASES: print('Release unsupported. Use something from %s' % DEFAULT_RELEASES.keys()) sys.exit(1) if args.distro not in DEFAULT_RELEASES[args.release]: print('Distro unsupported. Use something from %s' % DEFAULT_RELEASES[args.release]) sys.exit(1) release = args.release distribution = args.distro japi = Jenkins(jenkins_host, username=jenkins_user, password=jenkins_pass) jobs = get_jobs() if args.dry_run: print('Would start:', args.jobname) sys.exit(0) if args.jobname not in jobs: print('Job does not exist in config') sys.exit(1) # Racy, but whatever nextjob = japi.get_job_info('%s-source' % args.jobname)['nextBuildNumber'] job_no = japi.build_job('%s-source' % args.jobname, { 'release': release, 'distribution': distribution }) print('Build number:', nextjob)
def main(build_url, sleeptime=15, pushover=False, user=None, password=None): if pushover and not have_pushover: raise SystemExit("ERROR: to use pushover notifications, please `pip install python-pushover` and configure it.") job_name, build_no = get_job_name_and_build_number(build_url) logger.info("Job: %s", job_name) logger.info("Build Number: %s", build_no) jenkins_url = get_jenkins_base_url(build_url) logger.debug("Connecting to Jenkins...") if user is not None: logger.debug("Connecting to Jenkins as user %s ...", user) j = Jenkins(jenkins_url, user, password) else: logger.debug("Connecting to Jenkins anonymously...") j = Jenkins(jenkins_url) logger.debug("Connected.") if build_no is None: jobinfo = j.get_job_info(job_name) build_no = jobinfo['nextBuildNumber'] - 1 logger.info("Using latest build, #{b}".format(b=build_no)) build_url = get_formal_build_url(jenkins_url, job_name, build_no) print("Watching job {j} #{b} until completion <{u}>...".format(j=job_name, b=build_no, u=build_url)) while True: logger.debug("Getting build info...") buildinfo = j.get_build_info(job_name, build_no) if not buildinfo['building']: # job is not still building duration = datetime.timedelta(seconds=(buildinfo['duration'] / 1000)) if pushover: notify_pushover(buildinfo['result'], job_name, build_no, duration, build_url) if buildinfo['result'] == "SUCCESS": print("SUCCESS for {j} #{b} in {d} <{bu}>".format(j=job_name, b=build_no, bu=build_url, d=duration)) raise SystemExit(0) print("{r}: {j} #{b} failed in {d}".format(j=job_name, b=build_no, r=buildinfo['result'], d=duration)) raise SystemExit(1) else: duration = datetime.datetime.now() - datetime.datetime.fromtimestamp(buildinfo['timestamp'] / 1000) print("still running ({d})...".format(d=duration)) time.sleep(sleeptime)
class JenkinsControl(object): war=pjoin(here, 'tmp/jenkins.war') cli=pjoin(here, 'tmp/jenkins-cli.jar') home=pjoin(here, 'tmp/jenkins') def __init__(self, addr='127.0.0.1:60888', cport='60887'): self.addr, self.port = addr.split(':') self.url = 'http://%s' % addr self.py = Jenkins(self.url) def start_server(self): cmd = pjoin(here, './bin/start-jenkins.sh 1>/dev/null 2>&1') env={'JENKINS_HOME' : self.home, 'JENKINS_PORT' : self.port, 'JENKINS_CPORT' : self.cport, 'JENKINS_ADDR' : self.addr} check_call(cmd, shell=True, env=env) def shutdown_server(self): cmd = 'echo 0 | nc %s %s' % (self.addr, self.cport) check_call(cmd, shell=True) def clean_home(self): rmtree(self.home) def createjob(self, name, configxml_fn): self.py.create_job(name, open(configxml_fn).read()) def getjobs(self): return {i['name'] : i for i in self.py.get_jobs()} def enabled(self, name): return self.py.get_job_info(name)['buildable'] def job_etree(self, job): res = self.py.get_job_config(job) res = etree.fromstring(res) return res
class JenkinsBot(BotPlugin): def __init__(self): self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD) @botcmd def jenkins_list(self, mess, args): """List all jobs, optionally filter them using a search term.""" self.send(mess.getFrom(), u'/me is getting the list of jobs from Jenkins... ', message_type=mess.getType()) search_term = args.strip().lower() jobs = [job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower()] return self.format_jobs(jobs) @botcmd def jenkins_running(self, mess, args): """List all running jobs.""" self.send(mess.getFrom(), u'/me is getting the list of jobs from Jenkins... ', message_type=mess.getType()) jobs = [job for job in self.jenkins.get_jobs() if 'anime' in job['color']] return self.format_running_jobs(jobs) def format_jobs(self, jobs): if len(jobs) == 0: return u'No jobs found.' max_length = max([len(job['name']) for job in jobs]) return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs]).strip() def format_running_jobs(self, jobs): if len(jobs) == 0: return u'No running jobs.' jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs] return '\n\n'.join(['%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info]).strip()
from jenkins import Jenkins import pprint result_to_color = { 'SUCCESS': 'G', 'UNSTABLE': 'Y', 'FAILURE': 'R', 'BUILDING': 'B' } SERVER_URL = 'http://ci.attentec.se' JOB_NAME = 'Hacka-Traffic-Light' jenkins = Jenkins(SERVER_URL) jobs = jenkins.get_job_info(JOB_NAME, 0, False) last_build = jobs["lastBuild"] last_build_number = last_build["number"] NrOfStatuses = min(10, last_build_number) results = [None] * NrOfStatuses for i in range(len(results)): build_info = jenkins.get_build_info(JOB_NAME, last_build_number - i) if build_info["result"] is None: results[i] = 'BUILDING' else: results[i] = build_info["result"] print("build: {} result: {}".format(last_build_number - i, result_to_color[results[i]]))
class JenkinsTrigger(object): """ A class to trigger builds on Jenkins and print the results. :param token: The token we need to trigger the build. If you do not have this token, ask in IRC. """ def __init__(self, username, password, can_use_colour): """ Create the JenkinsTrigger instance. """ self.jobs = {} self.can_use_colour = can_use_colour and not os.name.startswith('nt') self.repo_name = get_repo_name() self.server = Jenkins(JENKINS_URL, username=username, password=password) def fetch_jobs(self): """ Get the job info for all the jobs """ for job_name in OpenLPJobs.Jobs: job_info = self.server.get_job_info(job_name) self.jobs[job_name] = job_info self.jobs[job_name][ 'nextBuildUrl'] = '{url}{nextBuildNumber}/'.format(**job_info) def trigger_build(self): """ Ask our jenkins server to build the "Branch-01-Pull" job. """ bzr = Popen(('bzr', 'whoami'), stdout=PIPE, stderr=PIPE) raw_output, error = bzr.communicate() # We just want the name (not the email). name = ' '.join(raw_output.decode().split()[:-1]) cause = 'Build triggered by %s (%s)' % (name, self.repo_name) self.fetch_jobs() self.server.build_job(OpenLPJobs.Branch_Pull, { 'BRANCH_NAME': self.repo_name, 'cause': cause }) def print_output(self, can_continue=False): """ Print the status information of the build triggered. """ print('Add this to your merge proposal:') print('-' * 80) bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE) raw_output, error = bzr.communicate() revno = raw_output.decode().strip() print('%s (revision %s)' % (get_repo_name(), revno)) failed_builds = [] for job in OpenLPJobs.Jobs: if not self.__print_build_info(job): if self.current_build: failed_builds.append( (self.current_build['fullDisplayName'], self.current_build['url'])) if not can_continue: print('Stopping after failure') break print('') if failed_builds: print('Failed builds:') for build_name, url in failed_builds: print(' - {}: {}console'.format(build_name, url)) else: print('All builds passed') def open_browser(self): """ Opens the browser. """ url = self.jenkins_instance.job(OpenLPJobs.Branch_Pull).info['url'] # Open the url Popen(('xdg-open', url), stderr=PIPE) def _get_build_info(self, job_name, build_number): """ Get the build info from the server. This method will check the queue and wait for the build. """ queue_info = self.server.get_queue_info() tries = 0 loop_count = 100 while queue_info and tries < loop_count: tries += 1 time.sleep(1) queue_info = self.server.get_queue_info() if tries >= loop_count: raise Exception( 'Build has not started yet, it may be stuck in the queue.') return self.server.get_build_info(job_name, build_number) def __print_build_info(self, job_name): """ This helper method prints the job information of the given ``job_name`` :param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class variables from the :class:`OpenLPJobs` class. """ job = self.jobs[job_name] print('{:<70} [WAITING]'.format(job['nextBuildUrl']), end='', flush=True) self.current_build = self._get_build_info(job_name, job['nextBuildNumber']) print('\b\b\b\b\b\b\b\b\b[RUNNING]', end='', flush=True) while self.current_build['building'] is True: time.sleep(0.5) self.current_build = self.server.get_build_info( job_name, job['nextBuildNumber']) result_string = self.current_build['result'] is_success = result_string == 'SUCCESS' if self.can_use_colour: if is_success: # Make 'SUCCESS' green. result_string = '{}{}{}'.format(Colour.GREEN_START, result_string, Colour.GREEN_END) else: # Make 'FAILURE' red. result_string = '{}{}{}'.format(Colour.RED_START, result_string, Colour.RED_END) print('\b\b\b\b\b\b\b\b\b[{:>7}]'.format(result_string)) return is_success
def gather(job_name, start_delimiter, end_delimiter, jenkins_username, jenkins_token): global server # job_name = 'enterprise_pe-acceptance-tests_integration-system_pe_full-upgrade_weekend_2016.4.x' # 'enterprise_pe-orchestrator_intn-van-sys-pez-multi_2016.4.x-2016.4.x' # 'enterprise_pe-modules-vanagon-suite_intn-van-sys-pez-multi_daily-pe-modules-2016.4.x' server = Jenkins( 'https://cinext-jenkinsmaster-enterprise-prod-1.delivery.puppetlabs.net', username=jenkins_username, password=jenkins_token) info = server.get_job_info(job_name) builds = [ server.get_build_info(job_name, build['number']) for build in info['builds'] ] last_job_check_lines = None counts = defaultdict(int) similar = set() for build in builds: output = server.get_build_console_output(job_name, build['number']) # print output try: req = jenkins.requests.Request( 'GET', 'https://cinext-jenkinsmaster-enterprise-prod-1.delivery.puppetlabs.net/view/__experimental/job/experimental_pe-acceptance-tests_integration-system_pe_full_nightly_2018.1.x/{}/LAYOUT=ubuntu1604-64mcd-64f-32f,LEGACY_AGENT_VERSION=NONE,PLATFORM=NONE,SCM_BRANCH=2018.1.x,UPGRADE_FROM=NONE,UPGRADE_TO_VERSION=NONE,label=beaker/testReport/(root)/acceptance_tests_01_post_install_tests/idempotent_rb' .format(build['number'])) html_doc = server.jenkins_open(req) except: continue soup = BeautifulSoup(html_doc, 'html.parser') # output = soup.pre.get_text() finder = get_strategy(output, start_delimiter=start_delimiter, end_delimiter=end_delimiter) found_lines = finder(output, job_name, build['number'], start_delimiter=start_delimiter, end_delimiter=end_delimiter) print("Found lines: ".format(found_lines)) if last_job_check_lines: seq = difflib.SequenceMatcher(a=last_job_check_lines, b=found_lines) if seq.ratio() == 1.0: counts['exact'] += 1 if seq.ratio() >= 0.7 and seq.ratio() < 1.0: counts['similar'] += 1 similar.append(found_lines) else: last_job_check_lines = found_lines if last_job_check_lines: click.echo('Last job check_lines were:') click.echo('\t{}'.format('\n\t'.join(last_job_check_lines))) if last_job_check_lines and 'exact' in counts: click.echo( 'There were {} jobs that failed with check_lines exactly the same as the last failed job:' .format(counts['exact'])) click.echo('\t{}'.format('\n\t'.join(last_job_check_lines))) if last_job_check_lines and 'similar' in counts: click.echo( 'There were {} jobs that failed with experienced similar check_lines as the last failed job:' .format(counts['exact'])) click.echo('\t{}'.format('\n\t'.join(last_job_check_lines))) for s in similar: click.echo('Additional Failed Job:') click.echo('\t{}'.format('\n\t'.join(s)))
class JenkinsBot(BotPlugin): def connect_to_jenkins(self): self.jenkins = Jenkins(JENKINS_URL, username=JENKINS_USERNAME, password=JENKINS_PASSWORD) @botcmd def jenkins_list(self, mess, args): """List all jobs, optionally filter them using a search term.""" self.connect_to_jenkins() search_term = args.strip().lower() jobs = self.search_job(search_term) return self.format_jobs(jobs) @botcmd def jenkins_running(self, mess, args): """List all running jobs.""" self.connect_to_jenkins() jobs = [job for job in self.jenkins.get_jobs() if 'anime' in job['color']] return self.format_running_jobs(jobs) @botcmd def jenkins_param(self, mess, args): """List Parameters for a given job.""" self.connect_to_jenkins() if len(args) == 0: return u'What Job would you like the parameters for?' if len(args.split()) > 1: return u'Please enter only one Job Name' if self.jenkins.get_job_info(args)['actions'][0] == {}: job_param = self.jenkins.get_job_info(args)['actions'][1]['parameterDefinitions'] else: job_param = self.jenkins.get_job_info(args)['actions'][0]['parameterDefinitions'] return self.format_params(job_param) @botcmd(split_args_with=None) def jenkins_build(self, mess, args): """Build a Jenkins Job with the given parameters Example: !jenkins build test_project FOO:bar """ self.connect_to_jenkins() if len(args) == 0: return u'What job would you like to build?' parameters = self.build_parameters(args[1:]) self.jenkins.build_job(args[0], parameters) running_job = self.search_job(args[0]) return 'Your job should begin shortly: {0}'.format(self.format_jobs(running_job)) def search_job(self, search_term): return [job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower()] def format_jobs(self, jobs): if len(jobs) == 0: return u'No jobs found.' max_length = max([len(job['name']) for job in jobs]) return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs]).strip() def format_running_jobs(self, jobs): if len(jobs) == 0: return u'No running jobs.' jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs] return '\n\n'.join(['%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info]).strip() def format_params(self, job): parameters = '' for param in range (0, len(job)): parameters = parameters + ("Type: {0}\nDescription: {1}\nDefault Value: {2}\nParameter Name: {3}\n_\n" .format(job[param]['type'], job[param]['description'], str(job[param]['defaultParameterValue']['value']), job[param]['name'])) return parameters def build_parameters(self, params): if len(params) == 0: return ast.literal_eval("{'':''}") parameters_list = "{'" for counter, param in enumerate(params): param = param.split(':') if counter < len(params) - 1: parameters_list = parameters_list + param[0] + "': '" + param[1] + "', '" else: parameters_list = parameters_list + param[0] + "': '" + param[1] + "'" parameters_list = parameters_list + '}' return ast.literal_eval(parameters_list)
class JenkinsBot(BotPlugin): """JenkinsBot is an Err plugin to manage Jenkins CI jobs from your chat platform like Slack.""" def __init__(self, bot): self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD) super().__init__(bot) @botcmd(split_args_with=None) def jenkins_build(self, msg, args): """Build the job specified by jobName. You can add params!""" # Params are passed like "key1=value1 key2=value2" params = {} try: for arg in args[1:]: params[arg.split('=', 1)[0]] = arg.split('=', 1)[1] except IndexError: return "I don't like that params! Try with this format: key1=value1 key2=value2..." try: self.jenkins.build_job(args[0].strip(), params) except NotFoundException: return "Sorry, I can't find the job. Typo maybe?" return ' '.join([ "The job", args[0].strip(), "has been sent to the queue to be built." ]) @botcmd def jenkins_cancel(self, msg, args): """Cancel a job in the queue by jobId.""" try: self.jenkins.cancel_queue(args.strip()) except NotFoundException: return "Sorry, I can't find the job. Maybe the ID does not exist." return "Job canceled from the queue." @botcmd def jenkins_list(self, msg, args): """List Jenkins jobs. You can filter with strings.""" self.send(msg.to, "I'm getting the jobs list from Jenkins...") search_term = args.strip().lower() jobs = [ job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower() ] return self.format_jobs(jobs) @botcmd def jenkins_describe(self, msg, args): """Describe the job specified by jobName.""" try: job = self.jenkins.get_job_info(args.strip()) except NotFoundException: return "Sorry, I can't find the job. Typo maybe?" return ''.join([ 'Name: ', job['name'], '\n', 'URL: ', job['url'], '\n', 'Description: ', 'None' if job['description'] is None else job['description'], '\n', 'Next Build Number: ', str('None' if job['nextBuildNumber'] is None else job['nextBuildNumber']), '\n', 'Last Successful Build Number: ', str('None' if job['lastBuild'] is None else job['lastBuild'] ['number']), '\n', 'Last Successful Build URL: ', 'None' if job['lastBuild'] is None else job['lastBuild']['url'], '\n' ]) @botcmd def jenkins_running(self, msg, args): """List running jobs.""" self.send(msg.to, "I will ask for the current running builds list!") jobs = self.jenkins.get_running_builds() return self.format_running_jobs(jobs) @botcmd(split_args_with=None) def jenkins_stop(self, msg, args): """Stop the building job specified by jobName and jobNumber.""" try: int(args[1].strip()) except ValueError: return "You have to specify the jobNumber: \"!jenkins stop <jobName> <jobNumber>" try: self.jenkins.stop_build(args[0].strip(), int(args[1].strip())) except NotFoundException: return "Sorry, I can't find the job. Typo maybe?" return ' '.join(["The job", args[0].strip(), "has been stopped."]) @botcmd def jenkins_queue(self, msg, args): """List jobs in queue.""" self.send(msg.to, "Getting the job queue...") jobs = self.jenkins.get_queue_info() return self.format_queue_jobs(jobs) def format_jobs(self, jobs): """Format jobs list""" if len(jobs) == 0: return "I haven't found any job." max_length = max([len(job['name']) for job in jobs]) return '\n'.join([ '%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs ]).strip() def format_queue_jobs(self, jobs): """Format queue jobs list""" if len(jobs) == 0: return "It seems that there is not jobs in queue." return '\n'.join([ '%s - %s (%s)' % (str(job['id']), job['task']['name'], job['task']['url']) for job in jobs ]).strip() def format_running_jobs(self, jobs): """Format running jobs list""" if len(jobs) == 0: return "There is no running jobs!" return '\n'.join([ '%s - %s (%s) - %s' % (str(job['number']), job['name'], job['url'], job['executor']) for job in jobs ]).strip()
class JenkinsTools(object): """ Jenkins操作工具类 """ def __init__(self, url, username, password): """ 初始化Jenkins连接信息 :param url: Jenkins地址 :param username: 登录用户名 :param password: 登录密码 """ try: self.session = Jenkins(url=url, username=username, password=password) except Exception: logger.exception('初始化Jenkins连接过程中发生异常,请检查!') @property def get_session(self): """ 返回Jenkins会话 :return: """ return self.session def get_job_info(self, job_name): """ 获取构建项目信息 :param job_name: 构建项目名称 :return: """ try: if self.session.job_exists(name=job_name): info = self.session.get_job_info(name=job_name) return info else: logger.warning( '[WARNING]: Jenkins构建项目"{}"并不存在,请检查!'.format(job_name)) sys.exit(1) except Exception: logger.exception('查看Jenkins构建项目"{}"过程中发生异常,请检查!'.format(job_name)) def get_job_info_by_regex(self, pattern): """ 正则表达式方式获取构建项目信息 :param pattern: 构建项目名称(正则表达式) :return: """ try: info_regex = self.session.get_job_info_regex(pattern=pattern) return info_regex except Exception: logger.exception('通过正则表达式"{}"查看匹配构建项目过程中发生异常,请检查!'.format(pattern)) def get_job_build_info(self, job_name, build_number): """ 通过构建项目名称及构建任务ID查看构建信息 :param job_name: 构建项目名称 :param build_number: 构建ID :return: """ try: result = self.session.get_build_info(name=job_name, number=build_number) return result except Exception: logger.exception('通过构建项目名称"{}"和构建ID"{}"查看构建信息过程中发生异常,请检查!'.format( job_name, build_number)) def rebase_build_info(self, job_name): """ 获取指定项目名称的自定义构建信息 :param job_name: 构建项目名称 :return: 构建信息自定义响应体 """ response_list = [] try: job_set = self.get_job_info(job_name) if job_set['lastBuild'] is not None: response_list.append( dict( ActionJob=job_set['displayName'], LastNumber=job_set['lastBuild']['number'], Building=self.get_job_build_info( job_set['displayName'], job_set['lastBuild']['number'])['building'], Result=self.get_job_build_info( job_set['displayName'], job_set['lastBuild']['number'])['result'], Time=trans_timestamp( self.get_job_build_info( job_set['displayName'], job_set['lastBuild']['number'])['timestamp']))) else: response_list.append( dict(ActionJob=job_set['displayName'], LastBuild="No latest build job info now.")) return response_list except Exception: logger.exception( '通过构建项目名称"{}"查看其自定义构建信息过程中发生异常,请检查!'.format(job_name)) def rebase_build_info_by_regex(self, pattern): """ 获取匹配正则表达式项目名称的自定义构建信息 :param pattern: 构建项目名称(正则表达式) :return: 构建信息自定义响应体 """ response_list = [] try: job_set = self.get_job_info_by_regex(pattern) if len(job_set) != 0: for i in job_set: if i['lastBuild'] is not None: response_list.append( dict(ActionJob=i['displayName'], LastNumber=i['lastBuild']['number'], Building=self.get_build_info( i['displayName'], i['lastBuild']['number'])['building'], Result=self.get_build_info( i['displayName'], i['lastBuild']['number'])['result'], Time=trans_timestamp( self.get_build_info( i['displayName'], i['lastBuild'] ['number'])['timestamp']), Operator=self.get_build_info( i['displayName'], i['lastBuild']['number'])['actions'][0] ['causes'][0]['shortDescription'])) else: response_list.append( dict(ActionJob=i['displayName'], LastBuild="No latest build job info now.")) return response_list except re.error: return "invalid pattern" except Exception: logger.exception( '通过正则表达式"{}"查看匹配项目的自定义构建信息过程中发生异常,请检查!'.format(pattern)) def stop_job_latest_build(self, job_name): """ 停止匹配正则表达式的构建项目的最近构建任务 :param job_name: 构建项目名称 :return: """ try: lastNumber = self.rebase_build_info( job_name=job_name)[0]['LastNumber'] self.session.stop_build(name=job_name, number=lastNumber) except Exception: logger.exception( '停止匹配正则表达式"{}"的构建项目的最近构建任务过程中发生异常,请检查!'.format(job_name))
class JenkinsBot(BotPlugin): """Basic Err integration with Jenkins CI""" min_err_version = '1.2.1' # max_err_version = '3.3.0' def get_configuration_template(self): return CONFIG_TEMPLATE def configure(self, configuration): if configuration is not None and configuration != {}: config = dict(chain(CONFIG_TEMPLATE.items(), configuration.items())) else: config = CONFIG_TEMPLATE super(JenkinsBot, self).configure(config) return def check_configuration(self, configuration): self.log.debug(configuration) for c in configuration: if c == 'URL': if not validators.url(configuration['URL']): raise ValidationException( 'JENKINS_URL is not a well formed URL') elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']: if len(configuration[c]) == 0 or not isinstance( configuration[c], str): raise ValidationException( "{} is a required string config setting".format(c)) elif c in ['CHATROOMS_NOTIFICATION']: if not isinstance(configuration[c], tuple): raise ValidationException( "{} should be of type tuple".format(c)) return def connect_to_jenkins(self): """Connect to a Jenkins instance using configuration.""" self.log.debug('Connecting to Jenkins ({0})'.format( self.config['URL'])) self.jenkins = Jenkins(url=self.config['URL'], username=self.config['USERNAME'], password=self.config['PASSWORD']) return def broadcast(self, mess): """Shortcut to broadcast a message to all elligible chatrooms.""" chatrooms = (self.config['CHATROOMS_NOTIFICATION'] if self.config['CHATROOMS_NOTIFICATION'] else self.bot_config.CHATROOM_PRESENCE) for room in chatrooms: self.send(self.build_identifier(room), mess, message_type='groupchat') return @webhook(r'/jenkins/notification') def handle_notification(self, incoming_request): if not self.config['RECEIVE_NOTIFICATION']: return "Notification handling is disabled \ (JENKINS_RECEIVE_NOTIFICATION = False)" self.log.debug(repr(incoming_request)) self.broadcast(self.format_notification(incoming_request)) return "OK" @botcmd def jenkins_list(self, mess, args): """List all jobs, optionally filter them using a search term.""" self.connect_to_jenkins() return self.format_jobs(self.jenkins.get_jobs(folder_depth=None)) @botcmd def jenkins_running(self, mess, args): """List all running jobs.""" self.connect_to_jenkins() jobs = [ job for job in self.jenkins.get_jobs() if 'anime' in job['color'] ] return self.format_running_jobs(jobs) @botcmd(split_args_with=None) def jenkins_param(self, mess, args): """List Parameters for a given job.""" if len(args) == 0: return 'What Job would you like the parameters for?' self.connect_to_jenkins() job = self.jenkins.get_job_info(args[0]) if job['actions'][1] != {}: job_param = job['actions'][1]['parameterDefinitions'] elif job['actions'][0] != {}: job_param = job['actions'][0]['parameterDefinitions'] else: job_param = [] return self.format_params(job_param) @botcmd(split_args_with=None) def jenkins_build(self, mess, args): """Build a Jenkins Job with the given parameters Example: !jenkins build test_project FOO:bar """ if len(args) == 0: # No Job name return 'What job would you like to build?' self.connect_to_jenkins() params = self.build_parameters(args[1:]) # Is it a parameterized job ? job = self.jenkins.get_job_info(args[0]) if job['actions'][0] == {} and job['actions'][1] == {}: self.jenkins.build_job(args[0]) else: self.jenkins.build_job(args[0], params) running_job = self.search_job(args[0]) return 'Your job should begin shortly: {0}'.format( self.format_jobs(running_job)) @botcmd(split_args_with=None) def build(self, mess, args): """Shortcut for jenkins_build""" return self.jenkins_build(mess, args) @botcmd(split_args_with=None) def jenkins_create(self, mess, args): """Create a Jenkins Job. Example: !jenkins create pipeline foo [email protected]:foo/bar.git """ if len(args) < 2: # No Job type or name return 'Oops, I need a type and a name for your new job.' if args[0] not in ('pipeline', 'multibranch'): return 'I\'m sorry, what type of job do you want ?' self.connect_to_jenkins() if args[0] == 'pipeline': self.jenkins.create_job( args[1], JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2])) elif args[0] == 'multibranch': return return def search_job(self, search_term): self.log.debug('Querying Jenkins for job "{0}"'.format(search_term)) return [ job for job in self.jenkins.get_jobs(folder_depth=None) if search_term.lower() == job['fullname'].lower() ] def format_running_jobs(self, jobs): if len(jobs) == 0: return 'No running jobs.' jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs] return '\n\n'.join([ '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info ]).strip() @staticmethod def format_jobs(jobs): if len(jobs) == 0: return 'No jobs found.' max_length = max([len(job['fullname']) for job in jobs]) return '\n'.join([ '%s (%s)' % (job['fullname'].ljust(max_length), job['url']) for job in jobs ]).strip() @staticmethod def format_params(job): """Format job parameters.""" if len(job) == 0: return 'This job is not parameterized.' PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}} Description: {{p.description}} Default Value: {{p.defaultParameterValue.value}} Parameter Name: {{p.name}} {% endfor %}""") return PARAM_TEMPLATE.render({'params': job}) @staticmethod def format_notification(body): body['fullname'] = body.get('fullname', body['name']) NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \ {{build.status}} for Job {{fullname}} ({{build.full_url}}) {% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \ ({{build.scm.branch}}){% endif %}""") return NOTIFICATION_TEMPLATE.render(body) @staticmethod def build_parameters(params): if len(params) > 0: return { param.split(':')[0]: param.split(':')[1] for param in params } return {'': ''}
def test_jenkins_jobs(): master = Jenkins('http://127.0.0.1:8080') test_job = master.get_job_info('test_job') assert test_job['name'] == 'test_job' assert test_job['buildable']
class JenkinsHelper: def __init__(self, url, username, password, key, configuration): self.configuration = configuration self.configuration_prefix = configuration.jenkins_configuration_prefix() self.grouped_components = configuration.jenkins_grouped_components() self.pullrequest_job = configuration.pullrequest_job() self.jenkins_configurations = Jenkins(url, username, password) self.build_components_jobs_matrix() self.sort_components() self.jenkins_builds = jenkinsapi.jenkins.Jenkins(url, username, password) # Getters def get_jobs(self): return self.jobs def get_components(self): return self.components def get_pull_request_builds(self): job = self.jenkins_builds.get_job(self.pullrequest_job) self.pullrequest_builds = {} for build_id in job.get_build_ids(): build = job[build_id] self.pullrequest_builds[build.buildno] = {} self.pullrequest_builds[build.buildno]['status'] = build.get_status() self.pullrequest_builds[build.buildno]['url'] = build.baseurl self.pullrequest_builds[build.buildno]['name'] = build.name revision = build.get_revision_branch()[0] self.pullrequest_builds[build.buildno]['revision'] = revision['SHA1'] self.pullrequest_builds[build.buildno]['revision_name'] = revision['name'] return self.pullrequest_builds # Helper methods def initial_jobs_info(self): wanted_jobs, wanted_ids = self.configuration.jenkins_jobs() jobs = self.wanted_jobs(wanted_jobs) return self.add_human_name_to_job(jobs, wanted_ids) def sort_components(self): self.components = OrderedDict(sorted(self.components.items(), key=lambda x: self.sorting_modification(x))) def build_components_jobs_matrix(self): self.jobs = self.initial_jobs_info() self.components = {} for job in self.jobs: groups = {} job_raw_components = self.jenkins_configurations.get_job_info(job['name'])["activeConfigurations"] job['components'] = {} for raw_component in job_raw_components: self.process_component(raw_component, job, groups) for name, group in groups.iteritems(): job['components'][name] = group self.add_group_to_components(name, group) def add_group_to_components(self, name, group): self.components[name] = {} self.components[name]['name'] = group['name'] self.components[name]['global_class'] = 'group' self.components[name]['type'] = 'group'; def process_component(self, raw_component, job, groups): name = raw_component['name'].replace(self.configuration_prefix, '') if name not in self.components: self.components[name] = {} self.components[name]['name'] = name job['components'][name] = {}; job['components'][name]['name'] = name; job['components'][name]['color'] = raw_component['color'] job['components'][name]['href'] = raw_component['url'] # Manage grouped components grouped_component = self.has_to_be_grouped(name, self.grouped_components) if grouped_component: self.components[name]['global_class'] = grouped_component + ' hide grouped' # Create component group entry group_name = grouped_component + '_grouped' if not group_name in groups: groups[group_name] = {'name': grouped_component, 'color': ''} groups[group_name]['color'] = self.logical_color_conjunction( groups[group_name]['color'], raw_component['color']) # Second level helper methods def wanted_jobs(self, wanted_jobs): jobs = self.jenkins_configurations.get_jobs() return [ job for job in jobs if job['name'] in wanted_jobs ] def add_human_name_to_job(self, jobs, wanted_jobs_ids): for i in range(len(jobs)): jobs[i]['short_name'] = wanted_jobs_ids[i] return jobs def has_to_be_grouped(self, name, grouped_configuration): for keyword in grouped_configuration: if name.find(keyword) == 0: return keyword return False def logical_color_conjunction(self, color1, color2): if (color1 == 'red' or color2 == 'red'): return 'red' if (color1 == 'yellow' or color2 == 'yellow'): return 'yellow' if (color1 == 'blue' or color2 == 'blue'): return 'blue' return 'white' def sorting_modification(self, value): if ('type' in value[1]) and (value[1]['type'] == 'group'): return value[1]['name'] return value[0] + "_"
class JC: def __init__(self): self.JCDirectoryLoc = '' self.JCBuiltFileLoc = '' self.JCServerConfFileLoc = '' self.JenkinsServerAddress = 'none' self.JenkinsServerPort = 'none' self.ServerHandler = None self.IpRegex = '''^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.( 25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.( 25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.( 25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)''' self.JCSelectedJobCommands = { '(enable)': ' - Enable the specified job on Jenkins Server', '(disable)': ' - Disable the specified job on Jenkins Server', '(build)': ' - Build the specified job on Jenkins Server', '(stat [*])': ' - Displays status and general information about the specified job', '(?)': ' - Displays list of available commands', '(??)': ' - Displays list of available commands verbosely', '(quit/exit)': ' - Quit Job configuration mode' } self.JigGlobalCommands = { '(show local jobs [*])': ' - Displays all jobs saved and waiting in your local machine to be created on server', '(show server jobs)': ' - Displays all jobs currently on your jenkins server', '(show build queue)': ' - Displays all jobs in build queue', '(delete local job)': ' - Deletes jobs on your local machine', '(delete server job)': ' - Deletes jobs on your jenkins server', '(reconfig server job)': ' - Reconfigures an existing job', '(select server job)': ' - Selects job and enter job configuration mode', '(connect)': ' - Connects to jenkins server', '(disconnect)': ' - Disconnects from jenkins server', '(create server job)': ' - Creates a new job on server ', '(?)': ' - Displays list of available commands', '(??)': ' - Displays list of available commands verbosely', '(exit / quit)': ' - Quit JC program' } def initialize(self): fh=open("C:\\Users\{0}\JC\controls".format(getuser())) for line in fh: if line.startswith('server.conf'): self.JCServerConfFileLoc=(line.split("=")[1]).strip() elif line.startswith('jobdir'): self.JCDirectoryLoc=(line.split("=")[1]).strip() elif line.startswith('built'): self.JCBuiltFileLoc=(line.split("=")[1]).strip() elif line.startswith('address'): self.JenkinsServerAddress=(line.split("=")[1]).strip() elif line.startswith('port'): self.JenkinsServerPort=(line.split("=")[1]).strip() fh.close() def display_introduction(self): ''' Display an introduction message for the program containing the version and status of development ''' print(" Welcome to JC 1.4") print("JC is a project which creates an interface to manage your Jenkins Server for your projects") print("This project is still under development ") def display_list_of_global_mode_commands(self, verbos=False, search_key=None): ''' Display list of available commands in global mode :param verbos: display description of command(s) if true :param search_key: display all commands starts with the 'key' param . default is None meaning all available commands ''' print("---------------Commands---------------") if search_key is None: for command, description in self.JigGlobalCommands.items(): print(command, description if verbos else '') else: for command, description in self.JigGlobalCommands.items(): if command.startswith('({0}'.format(search_key)): print(command, description if verbos else '') print("---------------------------------------") def display_list_of_selected_job_mode_commands(self, verbos=False, search_key=None): ''' Display list of available commands in selected job mode :param verbos: display description of command(s) if true :param search_key: display all commands starts with the 'key' param . default is None meaning all available commands ''' print("---------------Commands---------------") if search_key is None: for command, description in self.JCSelectedJobCommands.items(): print(command, description if verbos else '') else: for command, description in self.JCSelectedJobCommands.items(): if command.startswith('({0}'.format(search_key)): print(command, description if verbos else '') print("---------------------------------------") def show_local_jobs(self, Detail=False): ''' Display list of local jobs :param Detail: If True , Displays more detail about local jobs :return: ''' # TODO display format if len(listdir(self.JCDirectoryLoc)) == 0: print("No local job") else: if Detail: print("Status".ljust(8), "CRL".ljust(23), "CRS".ljust(23), "RCFG".ljust(23), "Name") print("-----".ljust(8), "--------".ljust(23), "--------".ljust(23), "--------".ljust(23), "-----") else: print("Status".ljust(8),"Name".ljust(20)) print("-----".ljust(8), "-----".ljust(33)) fhandle = open(self.JCBuiltFileLoc) for line in fhandle: line = line.strip() if line.startswith("#"): pass else: if Detail: Status=(line.split("@")[0]).ljust(8) CRL = ((line.split("@")[1]).split(".")[0]).ljust(23) CRS = ((line.split("@")[2]).split(".")[0] if line.split("@")[2]!='None' else 'None').ljust(23) RCFG = ((line.split("@")[3]).split(".")[0] if line.split("@")[3]!='None' else 'None').ljust(23) Name= (line.split("@")[4]) print(Status,CRL,CRS,RCFG,Name) else: Status = (line.split("@")[0]).ljust(8) Name= (line.split("@")[4]) print(Status,Name) fhandle.close() def connect_to_jenkins_server(self): # Because if there is a problem in reading server.conf file # both IP address and Port number becomes none # so we just check server address to be none or not fh=open("C:\\Users\{0}\JC\controls".format(getuser())) for line in fh: if line.startswith('address'): self.JenkinsServerAddress=(line.split("=")[1]).strip() elif line.startswith('port'): self.JenkinsServerPort=(line.split("=")[1]).strip() fh.close() if self.JenkinsServerAddress !='none': print("Connecting {0}:{1}".format(self.JenkinsServerAddress, self.JenkinsServerPort)) UserName = input("Username : "******"Password : "******"Connected successfully as {2}".format(self.JenkinsServerAddress, self.JenkinsServerPort, UserName)) except: self.ServerHandler = None print("Connection to server Failed") else: print("-Server configuration parameters are not defined properly") print("-Check server.conf for parameters and then use jcr.exe to set them") def is_connected(self): ''' Check whether we are connected to server or not ''' return True if self.ServerHandler else False def disconnect_from_jenkins_server(self, place=None): ''' Disconnect from the server :param place: Defines the place we are disconnecting . Displayed message can be different based on this parameter ''' # TODO Close the TCP PORT if self.ServerHandler == None: # Disconnect and Stay in the program if place is None: print("You are already disconnected") return self.ServerHandler = None # Disconnect while exiting the program print("You are disconnected successfully") def create_server_job(self, JobName): ''' Create a server job based on a config.xml file existing on the local machine :param JobName: job's name to be created ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return if not path.exists('{0}{1}{2}'.format(self.JCDirectoryLoc, JobName, '.config.xml')): print("-Job '{0}' config.xml file does not exist on your local machine".format(JobName)) print("First create a config.xml file for job {0} by jigjr command".format(JobName)) else: ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()] if JobName in ListServerJobs: print("-Job '{0}' already exists on the server".format(JobName)) AskingResult = self.asking_user_decision("Do you want to recreate job {0}?[y/n] : ".format(JobName)) if AskingResult: self.ServerHandler.delete_job(JobName) print("-Deleting job '{0}' from server ..".format(JobName)) fhandle = open(self.JCDirectoryLoc + JobName + ".config.xml") SelectedJobXml = fhandle.read() fhandle.close() self.ServerHandler.create_job(JobName, SelectedJobXml) print("-Job '{0}' recreated successfully".format(JobName)) # Recreate a job is similar to reconfigure that job update_built_file(self.JCBuiltFileLoc, 'update-reconfigure-date', JobName, reconfig_date=datetime.now()) else: AskingResult = self.asking_user_decision("Sure creating job {0}?[y/n] : ".format(JobName)) if AskingResult: fhandle = open(self.JCDirectoryLoc + JobName + ".config.xml") SelectedJobXml = fhandle.read() fhandle.close() self.ServerHandler.create_job(JobName, SelectedJobXml) print("-Job '{0}' created successfully".format(JobName)) update_built_file(self.JCBuiltFileLoc, 'update-server-create-date', JobName, server_creation_date=datetime.now()) def reconfigure_server_job(self, JobName, LocalConfigJobName=None): ''' Reconfigure a server job :param JobName: Server job to be configured :param LocalConfigJobName: If None , JobName.config.xml file is searched in local machine , else, LocalConfigJobName.config.xml is searched ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()] if JobName not in ListServerJobs: print("-Job '{0}' does not exist on the server".format(JobName)) else: ListLocalJobs = [job.split(".")[0] for job in listdir(self.JCDirectoryLoc)] # If the LocalConfigJobName is not specified use the JobName as defualt LocalConfigJobName = JobName if LocalConfigJobName is None else LocalConfigJobName if LocalConfigJobName not in ListLocalJobs: print("-Job {0} config.xml file does not exist in your local machine".format(LocalConfigJobName)) else: print("{0}.config.xml found".format(LocalConfigJobName)) AskingResult = self.asking_user_decision("Sure reconfiguring job {0}?[y/n] : ".format(JobName)) if AskingResult: fhandle = open(self.JCDirectoryLoc + LocalConfigJobName + ".config.xml") SelectedJobXml = fhandle.read() fhandle.close() self.ServerHandler.reconfig_job(LocalConfigJobName, SelectedJobXml) print("-Job '{0}' reconfigured successfully".format(LocalConfigJobName)) update_built_file(self.JCBuiltFileLoc, 'update-reconfigure-date', LocalConfigJobName, reconfig_date=datetime.now()) def show_build_queue(self): ''' Display list of jobs which are currently under building process ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return else: BuildQueue = self.ServerHandler.get_queue_info() if len(BuildQueue) == 0: print("No job in build queue") return else: BuildQueueCounter = 1 for job in BuildQueue: jobInfo = self.ServerHandler.get_job_info(job['task']['name']) print("{0}: {1}\tBuilding No: {2}".format(BuildQueueCounter, job["task"]["name"], jobInfo['nextBuildNumber'])) BuildQueueCounter += 1 def show_server_jobs(self): ''' Display list of jobs currently configured on the server ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return else: if len(self.ServerHandler.get_jobs()) == 0: print("No job currently on the server") else: ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()] # This list is to reduce the latency of display of all jobs # First collect information of all jobs then display ReadyList = [] for job in ListServerJobs: JobInfo = self.ServerHandler.get_job_info(job) JobStatus = 'Disabled' if JobInfo['disabled'] else 'Enabled' JobTotalBuilds = "0" if JobInfo['lastBuild'] is None else JobInfo['lastBuild']['number'] JobLastBuild = "None" if JobInfo['lastBuild'] is None else datetime.fromtimestamp( self.ServerHandler.get_build_info(job, JobInfo['lastBuild']['number'])['timestamp'] / 1000) ReadyList.append([JobStatus, JobTotalBuilds, JobLastBuild, job]) print("Status".ljust(8), "Build".ljust(7), "Timestamp".ljust(22), "Name".ljust(20)) print("-----".ljust(8), "-----".ljust(7), "------".ljust(22), "----".ljust(20)) for j in ReadyList: print(j[0].ljust(9), str(j[1]).ljust(6),('None' if str(j[2]) == 'None' else str(j[2]).split(".")[0]).ljust(22), j[3].ljust(20)) def delete_local_job(self, JobName): ''' Delete local jobs ''' LocalJobs = [job.split(".")[0] for job in listdir(self.JCDirectoryLoc)] if JobName not in LocalJobs: print("-Job '{0}' does not exist in your local machine".format(JobName)) return else: AskingResult = self.asking_user_decision("Sure deleting job '{0}'?[y/n] : ".format(JobName)) if AskingResult: remove(self.JCDirectoryLoc + JobName + ".config.xml") print("-Job '{0}' removed successfully from your local machine".format(JobName)) update_built_file(self.JCBuiltFileLoc, 'delete', JobName) def delete_server_job(self, JobName): ''' Delete Specified server job ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return else: ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()] if JobName not in ListServerJobs: print("-Job '{0}' does not exist in Jenkins Server".format(JobName)) return else: AskingResult = self.asking_user_decision("Sure deleting job '{0}'?[y/n]: ".format(JobName)) if AskingResult: self.ServerHandler.delete_job(JobName) print("-Job '{0}' removed successfully from server".format(JobName)) update_built_file(self.JCBuiltFileLoc, 'update-deploy-status-ND', JobName) def disable_server_job(self, JobName): ''' Disable specified server job ''' JobState = self.ServerHandler.get_job_info(JobName)['disabled'] if JobState: print("-Job '{0}' is already disabled".format(JobName)) return self.ServerHandler.disable_job(JobName) print("-Job '{0}' successfully disabled".format(JobName)) def enable_server_job(self, JobName): ''' Enable specified server job ''' JobState = self.ServerHandler.get_job_info(JobName)['disabled'] if not JobState: print("-Job '{0}' is already enabled".format(JobName)) return self.ServerHandler.enable_job(JobName) print("-Job '{0}' successfully enabled".format(JobName)) def build_server_job(self, JobName): ''' Build specified server job ''' JobState = self.ServerHandler.get_job_info(JobName)['disabled'] if JobState: print("-Job '{0}' is disabled and cannot built".format(JobName)) else: self.ServerHandler.build_job(JobName) print("-Job '{0}' successfully built".format(JobName)) def stat_server_job(self, JobName, Detail=False): ''' Display status of the selected job :param Detail: If * specified , more detail about job is displayed ''' # Because building a job can take long time we do not display the status # until the building process gets done BuildQueue = self.ServerHandler.get_queue_info() for job in BuildQueue: if JobName == job["task"]["name"]: print("-Job '{0}' is under building process".format(JobName)) return JobInfo = self.ServerHandler.get_job_info(JobName) JobName_Sta = "Name: {0}".format(JobName) JobStatus_Sta = "Status: {0}".format('Disabled' if JobInfo['disabled'] else 'Enabled') JobTotalBuilds_Sta = "TotalBuilds: {0}".format( "0" if JobInfo['lastBuild'] is None else JobInfo['lastBuild']['number']) JobLastBuild_Sta = "LastBuild: {0}".format("None" if JobInfo['lastBuild'] is None else datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastBuild']['number'])['timestamp'] / 1000)) JobFirstBuild_Sta = "FirstBuild: {0}".format("None" if JobInfo['lastBuild'] is None else datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastBuild']['number'])['timestamp'] / 1000)) JobLastCompletedBuild_Sta = "LastCompletedBuild: {0}".format( "None" if JobInfo['lastCompletedBuild'] is None else str(datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastCompletedBuild']['number'])[ 'timestamp'] / 1000)).split(".")[0]) JobLastFailedBuild_Sta = "LastFailedBuild: {0}".format( "None" if JobInfo['lastFailedBuild'] is None else str(datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastFailedBuild']['number'])['timestamp'] / 1000)).split(".")[0]) JobLastStableBuild_Sta = "LastStableBuild: {0}".format( "None" if JobInfo['lastStableBuild'] is None else str(datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastStableBuild']['number'])['timestamp'] / 1000)).split(".")[0]) JobLastSuccessfulBuild_Sta = "LastSuccessfulBuild: {0}".format( "None" if JobInfo['lastSuccessfulBuild'] is None else str(datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastSuccessfulBuild']['number'])[ 'timestamp'] / 1000)).split(".")[0]) JobLastUnstableBuild_Sta = "LastUnstableBuild: {0}".format( "None" if JobInfo['lastUnstableBuild'] is None else str(datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastUnstableBuild']['number'])['timestamp'] / 1000)).split(".")[0]) JobLastUnsuccessfulBuild_Sta = "LastUnsuccessfulBuild: {0}".format( "None" if JobInfo['lastUnsuccessfulBuild'] is None else str(datetime.fromtimestamp( self.ServerHandler.get_build_info(JobName, JobInfo['lastUnsuccessfulBuild']['number'])[ 'timestamp'] / 1000)).split(".")[0]) print(JobName_Sta) print(JobStatus_Sta) print(JobTotalBuilds_Sta) print(JobLastBuild_Sta) print(JobLastStableBuild_Sta) print(JobLastCompletedBuild_Sta) if Detail: print(JobFirstBuild_Sta) print(JobLastFailedBuild_Sta) print(JobLastSuccessfulBuild_Sta) print(JobLastUnstableBuild_Sta) print(JobLastUnsuccessfulBuild_Sta) def select_server_job(self, JobName): ''' Select a server job and enter selected job mode ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return else: ListServerJobs = [server_job["name"] for server_job in self.ServerHandler.get_jobs()] if JobName not in ListServerJobs: print("-Job '{0}' not exist in Jenkins Server".format(JobName)) return else: SelectedJobSession = PromptSession( lexer=PygmentsLexer(SqlLexer), completer=selected_job_command_completer) while True: try: UserCommand = SelectedJobSession.prompt("(" + JobName + ')## ') UserCommand = (sub(' +', ' ', UserCommand)).strip() if UserCommand.startswith("??"): keyValue = (UserCommand.split("??")[1].strip()) if keyValue == '': jc.display_list_of_selected_job_mode_commands(verbos=True) else: jc.display_list_of_selected_job_mode_commands(search_key=keyValue, verbos=True) elif UserCommand.startswith("?"): keyValue = (UserCommand.split("?")[1].strip()) if keyValue == '': jc.display_list_of_selected_job_mode_commands() else: jc.display_list_of_selected_job_mode_commands(search_key=keyValue) elif UserCommand == "quit" or UserCommand == "exit": return elif UserCommand == "enable": self.enable_server_job(JobName) elif UserCommand == "disable": self.disable_server_job(JobName) elif UserCommand == "build": self.build_server_job(JobName) elif UserCommand == 'stat *': self.stat_server_job(JobName, Detail=True) elif UserCommand == 'stat': self.stat_server_job(JobName) elif UserCommand == "": pass else: print("%Invalid Command") except KeyboardInterrupt: break except EOFError: break except: print("There was a problem in program") return def get_whoami(self): ''' Display who is connected to server ''' if self.ServerHandler is None: print("Your are not connected to server") print("First connect by 'connect' command") return else: UserInfo = self.ServerHandler.get_whoami() print("Full Name : ", UserInfo["fullName"]) print("Id : ", UserInfo["id"]) def asking_user_decision(self, displayMessage): ''' This process is repeated many times in the code asking the user for yes/no answer so this process is turned into a function for simplicity :param displayMessage: Message to be displayed for asking user his/her decision ''' while True: UserDecision = input(displayMessage) if UserDecision.lower() in "y yes ye": return True elif UserDecision.lower() in "n no": return False def get_job_directory(self): return self.JCDirectoryLoc
class JenkinsNotifier(BotPlugin): """JenkinsBot is an Err plugin to manage Jenkins CI jobs from your chat platform like Slack.""" status = {'blue':'SUCCESS', 'blue_anime':'IN PROGRESS','red': 'FAILED', 'red_anime': 'IN PROGRESS', 'disabled': 'DISABLED', 'aborted':'ABORTED', 'notbuilt': 'NOTBUILT', 'yellow': 'UNSTABLE'} failedjobsstring = " " def __init__(self, bot, name): self.jenkins = Jenkins(JENKINS_URL, JENKINS_USERNAME, JENKINS_TOKEN) super().__init__(bot, name) @botcmd(split_args_with=None) def jn_build(self, msg, args): """Build the job specified by jobName. You can add params!""" # Params are passed like "key1=value1 key2=value2" params = {} #try: # for arg in args[1:]: # params[arg.split('=', 1)[0]] = arg.split('=', 1)[1] #except IndexError: # return "I don'G like that params! Try with this format: key1=value1 key2=value2..." jobName = ''.join([args[0],' ',args[1]]) #TODO handle jobname with spaces in it, space is cosidered argument splitter try: self.jenkins.build_job(jobName, params) except NotFoundException: return ' '.join(["Sorry, I can't find the job. Typo maybe?"," ARGS=",jobName]) return ' '.join(["The job", args[0].strip(), "has been sent to the queue to be built."]) @botcmd def jn_cancel(self, msg, args): """Cancel a job in the queue by jobId.""" try: self.jenkins.cancel_queue(args.strip()) except NotFoundException: return "Sorry, I can't find the job. Maybe the ID does not exist." return "Job canceled from the queue." @botcmd def jn_list(self, msg, args): """List Jenkins jobs. You can filter with strings.""" self.send(msg.to, "I'm getting the jobs list from Jenkins...") search_term = args.strip().lower() jobs = [job for job in self.jenkins.get_jobs() if search_term.lower() in job['name'].lower()] return self.format_jobs(jobs) @botcmd def jn_status(self, msg, args): """List Jenkins jobs with their current status.""" self.send(msg.to, "I'm getting the jobs with status Jenkins...") search_term = args.strip().lower() jobs = [job for job in self.jenkins.get_jobs() if search_term.lower() in job['fullname'].lower()] return self.format_job_status(jobs) @botcmd def jn_describe(self, msg, args): """Describe the job specified by jobName.""" try: job = self.jenkins.get_job_info(args.strip()) except NotFoundException: return "Sorry, I can't find the job. Typo maybe?" return ''.join([ 'Name: ', job['name'], '\n', 'URL: ', job['url'], '\n', 'Description: ', 'None' if job['description'] is None else job['description'], '\n', 'Next Build Number: ', str('None' if job['nextBuildNumber'] is None else job['nextBuildNumber']), '\n', 'Last Successful Build Number: ', str('None' if job['lastBuild'] is None else job['lastBuild']['number']), '\n', 'Last Successful Build URL: ', 'None' if job['lastBuild'] is None else job['lastBuild']['url'], '\n' ]) @botcmd def jn_running(self, msg, args): """List running jobs.""" self.send(msg.to, "I will ask for the current running builds list!") jobs = self.jenkins.get_running_builds() return self.format_running_jobs(jobs) @botcmd(split_args_with=None) def jn_stop(self, msg, args): """Stop the building job specified by jobName and jobNumber.""" try: int(args[1].strip()) except ValueError: return "You have to specify the jobNumber: \"!jenkins stop <jobName> <jobNumber>" try: self.jenkins.stop_build(args[0].strip(), int(args[1].strip())) except NotFoundException: return "Sorry, I can't find the job. Typo maybe?" return ' '.join(["The job", args[0].strip(), "has been stopped."]) @botcmd def jn_queue(self, msg, args): """List jobs in queue.""" self.send(msg.to, "Getting the job queue...") jobs = self.jenkins.get_queue_info() return self.format_queue_jobs(jobs) @botcmd def jn_msgtimer(self, msg, args): """Sends messages at fix intervals.""" yield "Starting timer" self.start_poller(5, self.my_callback) self.send(msg.to, "Boo! Bet you weren't expecting me, were you?", ) def my_callback(self): self.log.info('I am called every 5sec') self.send(self.build_identifier("#errbottestchannel"), "I am called every 5sec", ) @botcmd def jn_failed(self, msg, args): """List Jenkins jobs with failed status.""" self.send(msg.to, "I'm getting the failed jobs ...") failedJobs = [] search_term = args.strip().lower() jobs = [job for job in self.jenkins.get_jobs() if search_term.lower() in job['fullname'].lower()] for job in jobs: if self.status[job['color']] == 'FAILED': failedJobs.append(job) return self.format_job_status(failedJobs) # SUPPORT FUNCTIONS START HERE def format_jobs(self, jobs): """Format jobs list""" if len(jobs) == 0: return "I haven't found any job." max_length = max([len(job['name']) for job in jobs]) return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs]).strip() def format_queue_jobs(self, jobs): """Format queue jobs list""" if len(jobs) == 0: return "It seems that there is not jobs in queue." return '\n'.join(['%s - %s (%s)' % (str(job['id']), job['task']['name'], job['task']['url']) for job in jobs]).strip() def format_running_jobs(self, jobs): """Format running jobs list""" if len(jobs) == 0: return "There is no running jobs!" return '\n'.join(['%s - %s (%s) - %s' % (str(job['number']), job['name'], job['url'], job['executor']) for job in jobs]).strip() @botcmd def jn_queue(self, msg, args): """List jobs in queue.""" self.send(msg.to, "Getting the job queue...") jobs = self.jenkins.get_queue_info() return self.format_queue_jobs(jobs) def format_jobs(self, jobs): """Format jobs list""" if len(jobs) == 0: return "I haven't found any job." max_length = max([len(job['name']) for job in jobs]) return '\n'.join(['%s (%s)' % (job['name'].ljust(max_length), job['url']) for job in jobs]).strip() def format_queue_jobs(self, jobs): """Format queue jobs list""" if len(jobs) == 0: return "It seems that there is not jobs in queue." return '\n'.join(['%s - %s (%s)' % (str(job['id']), job['task']['name'], job['task']['url']) for job in jobs]).strip() def format_running_jobs(self, jobs): """Format running jobs list""" if len(jobs) == 0: return "There is no running jobs!" return '\n'.join(['%s - %s (%s) - %s' % (str(job['number']), job['name'], job['url'], job['executor']) for job in jobs]).strip() def format_job_status(self, jobs): """Format job status""" if len(jobs) == 0: return "there are no jobs to return" return '\n'.join(['%s (%s)' % (job['fullname'], self.status[job['color']]) for job in jobs]).strip()
class jenkinscls(object): def __init__(self): self.url = config.JENKINS_URL self.username = config.JENKINS_NAME self.token = config.JENKINS_TOKEN self.j = Jenkins(config.JENKINS_URL, username=config.JENKINS_NAME, password=config.JENKINS_TOKEN) def getjobnames(self, strval=''): rs = {r'...': r'/'} s = utils.multiple_replace(str(strval), rs).split('/') return s[0], "/".join(s[1:]) def getlenstr(self, strval, n): return str(strval)[0:n] def getstatus(self, strval): if str(strval) == 'FAILURE': return 'error' elif str(strval) == 'ABORTED': return 'aborted' elif str(strval) == 'SUCCESS': return 'success' else: return 'started' def edit_userjob_config(self, jn, obj): n, r = self.getjobnames(jn) try: desobj = callback() desobj.des = obj['description'] desobj.callback_url = "" desobj.build_id = '' desobj.duration = '' desobj.namespace = n desobj.image_name = obj['image_name'] desobj.repo_name = r desobj.status = '' desobj.tag = obj['build_config']['tag_configs']['docker_repo_tag'] desobj.time = '' ss = xmltodict.parse(self.getbasejob_config()) jsonpickle.set_preferred_backend('json') ss['project']['description'] = jsonpickle.encode(desobj) ss['project']['properties']['com.tikal.hudson.plugins.notification.HudsonNotificationProperty']['endpoints'] \ ['com.tikal.hudson.plugins.notification.Endpoint']['url'] = config.JOBHOOKURL ss['project']['scm']['userRemoteConfigs']['hudson.plugins.git.UserRemoteConfig'] \ ['url'] = obj['build_config']['code_repo_clone_url'] ss['project']['scm']['branches']['hudson.plugins.git.BranchSpec'] \ ['name'] = '*/' + obj['build_config']['tag_configs']['code_repo_type_value'] ss['project']['builders']['hudson.tasks.Shell'][ 'command'] = config.JOBCOMMON1 ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['registry'] \ ['url'] = config.REGISTRYURL b = str(obj['build_config']['tag_configs']['build_cache_enabled']) ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['noCache'] \ = ('true' if b == 'false' else 'false') ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['dockerfilePath'] \ = obj['build_config']['tag_configs']['dockerfile_location'] ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['repoTag'] \ = obj['build_config']['tag_configs']['docker_repo_tag'] ss['project']['builders']['com.cloudbees.dockerpublish.DockerBuilder']['repoName'] \ = obj['image_name'] return xmltodict.unparse(ss) except Exception as e: print e.message def edit_docker_load_job_config(self, obj): try: # {docker_login} && docker import {httpfilename} {imagename} && docker push {imagename} ss = xmltodict.parse(self.getdocker_load_config()) desobj = callback() desobj.des = obj['export_file_url'] desobj.callback_url = obj['post_callback_url'] desobj.build_id = obj['build_id'] desobj.duration = '' desobj.namespace = "" desobj.repo_name = "" desobj.image_name = obj['image_name'] desobj.status = '' desobj.tag = obj['tag'] desobj.time = '' jsonpickle.set_preferred_backend('json') ss['project']['description'] = jsonpickle.encode(desobj) ss['project']['properties']['com.tikal.hudson.plugins.notification.HudsonNotificationProperty']['endpoints'] \ ['com.tikal.hudson.plugins.notification.Endpoint']['url'] = config.JOBHOOKURL tempstr = str( ss['project']['builders']['hudson.tasks.Shell']['command']) s = { r'{docker_login}': config.JOBCOMMON1, r'{httpfilename}': obj['export_file_url'], r'{imagename}': config.REGISTRYNAME + '/' + obj['image_name'] + ':' + obj['tag'] } ss['project']['builders']['hudson.tasks.Shell'][ 'command'] = utils.multiple_replace(tempstr, s) return xmltodict.unparse(ss) except Exception as e: print e.message def edit_docker_sync_job_config(self, obj): try: # {docker_login} && docker pull {oldimage} && docker tag {oldimage} {newimage} && docker push {newimage} ss = xmltodict.parse(self.getdocker_sync_config()) jsonUtil = JsonUtil() c = jsonUtil.parseJsonString(config.CLOUD_CONFIG) cid = obj['sync_cloud_id'] desobj = callback() desobj.des = "" desobj.callback_url = obj['post_callback_url'] desobj.build_id = '' desobj.duration = '' desobj.namespace = "" desobj.repo_name = obj['sync_cloud_id'] # 把cloudid 临时存在 这 desobj.image_name = obj['image_name'] desobj.status = '' desobj.tag = obj['tag'] desobj.time = '' jsonpickle.set_preferred_backend('json') ss['project']['description'] = jsonpickle.encode(desobj) ss['project']['properties']['com.tikal.hudson.plugins.notification.HudsonNotificationProperty']['endpoints'] \ ['com.tikal.hudson.plugins.notification.Endpoint']['url'] = config.JOBHOOKURL+'?cloudid='+obj['sync_cloud_id'] tempstr = str( ss['project']['builders']['hudson.tasks.Shell']['command']) s = { r'{docker_login}': c[cid]['login_common'], r'{oldimage}': config.REGISTRYNAME + '/' + obj['image_name'] + ':' + obj['tag'], r'{newimage}': c[cid]['registry_name'] + '/' + obj['image_name'] + ':' + obj['tag'] } ss['project']['builders']['hudson.tasks.Shell'][ 'command'] = utils.multiple_replace(tempstr, s) return xmltodict.unparse(ss) except Exception as e: print e.message def updateconfig_buildid(self, jn, imagename, build_id, callback_url): try: ss = xmltodict.parse(self.j.get_job_config(jn)) jsonpickle.set_preferred_backend('json') desobj = jsonpickle.decode(ss['project']['description']) if str(desobj.build_id) == str(build_id): return True desobj.build_id = build_id desobj.callback_url = callback_url desobj.image_name = imagename ss['project']['description'] = jsonpickle.encode(desobj) self.j.reconfig_job(jn, xmltodict.unparse(ss)) return True except Exception as e: print e.message return False @gen.coroutine def posthook(self, obj): # s = {r'/': r'...'} jn = obj['name'] bid = str(obj['build']['number']) # n, r = self.getjobnames(jn) re = hook() try: info = self.j.get_build_info(jn, int(bid)) if self.j.job_exists(jn): ss = xmltodict.parse(self.j.get_job_config(jn)) jsonpickle.set_preferred_backend('json') if isinstance(jsonpickle.decode(ss['project']['description']), callback): desobj = jsonpickle.decode(ss['project']['description']) re.namespace = desobj.namespace re.repo_name = desobj.repo_name re.build_id = str(obj['build']['number']) re.status = self.getstatus(obj['build']['status']) re.duration = info['duration'] re.tag = desobj.tag re.time = datetime.now() re.callurl = desobj.callback_url except Exception as e: print e.message re = None raise gen.Return(re) @gen.coroutine def post_docker_load_hook(self, obj): jn = obj['name'] bid = str(obj['build']['number']) re = postimage() try: # info = self.j.get_build_info(jn, int(bid)) if self.j.job_exists(jn): ss = xmltodict.parse(self.j.get_job_config(jn)) jsonpickle.set_preferred_backend('json') if isinstance(jsonpickle.decode(ss['project']['description']), callback): desobj = jsonpickle.decode(ss['project']['description']) re.image_name = desobj.image_name re.status = self.getstatus(obj['build']['status']) re.tag = desobj.tag re.export_file_url = desobj.des re.time = datetime.now() re.build_id = desobj.build_id re.post_callback_url = desobj.callback_url if re.status != 'error' and config.JENKINS_IMAGEOPTJOB_DELETE == 'true': self.j.delete_job(jn) except Exception as e: print e.message re = None raise gen.Return(re) @gen.coroutine def post_docker_sync_hook(self, obj, cloudid): jn = obj['name'] # bid = str(obj['build']['number']) jsonUtil = JsonUtil() c = jsonUtil.parseJsonString(config.CLOUD_CONFIG) j = Jenkins(c[cloudid]['jenkins_url'], username=c[cloudid]['jenkins_name'], password=c[cloudid]['jenkins_token']) re = postimagesync() try: if j.job_exists(jn): ss = xmltodict.parse(j.get_job_config(jn)) jsonpickle.set_preferred_backend('json') if isinstance(jsonpickle.decode(ss['project']['description']), callback): desobj = jsonpickle.decode(ss['project']['description']) re.image_name = desobj.image_name re.status = self.getstatus(obj['build']['status']) re.sync_cloud_id = desobj.repo_name re.tag = desobj.tag re.time = datetime.now() re.post_callback_url = desobj.callback_url if re.status != 'error' and config.JENKINS_IMAGEOPTJOB_DELETE == 'true': j.delete_job(jn) except Exception as e: print e.message re = None raise gen.Return(re) @gen.coroutine def createjob(self, jobname, obj): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) try: if self.j.job_exists(jn): re = createrespo(n, r, '工程已存在', 'error', datetime.now()) self.j.create_job(jn, self.edit_userjob_config(jn, obj)) re = createrespo(n, r, '', 'success', datetime.now()) except Exception as e: print e.message re = createrespo(n, r, '', 'error', datetime.now()) raise gen.Return(re) @gen.coroutine def create_docker_load_job(self, obj): # s = {r'/': r'...'} # jn = utils.multiple_replace(jobname, s) s = utils.randomstr(8) jn = '__docker_load_job_' + s re = postimage() re.created_at = datetime.now() re.image_name = obj['image_name'] re.build_id = str(obj['build_id']) re.post_callback_url = obj['post_callback_url'] re.tag = obj['tag'] re.status = 'started' try: if self.j.job_exists(jn): jn = jn + utils.randomstr(4) x = self.edit_docker_load_job_config(obj) self.j.create_job(jn, x) yield gen.sleep(0.5) self.j.build_job(jn) x = self.edit_docker_load_job_config(obj) self.j.create_job(jn, x) yield gen.sleep(0.5) self.j.build_job(jn) except Exception as e: print e.message re.status = 'error' raise gen.Return(re) @gen.coroutine def create_docker_sync_job(self, obj): # s = {r'/': r'...'} # jn = utils.multiple_replace(jobname, s) s = utils.randomstr(8) jn = '__docker_sync_job_' + s cid = obj['sync_cloud_id'] jsonUtil = JsonUtil() c = jsonUtil.parseJsonString(config.CLOUD_CONFIG) j = Jenkins(c[cid]['jenkins_url'], username=c[cid]['jenkins_name'], password=c[cid]['jenkins_token']) re = postimagesync() re.time = datetime.now() re.sync_cloud_id = obj['sync_cloud_id'] re.image_name = obj['image_name'] re.post_callback_url = obj['post_callback_url'] re.tag = obj['tag'] re.status = 'started' try: if j.job_exists(jn): jn = jn + utils.randomstr(4) j.create_job(jn, self.edit_docker_sync_job_config(obj)) yield gen.sleep(0.5) j.build_job(jn) j.create_job(jn, self.edit_docker_sync_job_config(obj)) yield gen.sleep(0.5) j.build_job(jn) except Exception as e: print e.message re.status = 'error' raise gen.Return(re) @gen.coroutine def editjob(self, jobname, obj): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) try: if self.j.job_exists(jn): self.j.reconfig_job(jn, self.edit_userjob_config(jn, obj)) re = createrespo(n, r, '', 'success', datetime.now()) else: re = createrespo(n, r, 'repo is not find', 'error', datetime.now()) except Exception as e: print e.message re = createrespo(n, r, '', 'error', datetime.now()) raise gen.Return(re) @gen.coroutine def getjobinfo(self, jobname): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) re = jobinfo() try: if self.j.job_exists(jn): re.namespace = n re.repo_name = r re.info = self.j.get_job_info(jn) except Exception as e: print e.message re.namespace = n re.repo_name = r re.info = "" raise gen.Return(re) @gen.coroutine def deljob(self, jobname): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) try: if self.j.job_exists(jn): self.j.delete_job(jn) re = delrespo(n, r, 'success') except Exception as e: print e.message re = delrespo(n, r, 'error') raise gen.Return(re) @gen.coroutine def stopbuild(self, jobname, build_id): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) try: if self.j.job_exists(jn) and self.j.get_build_info( jn, int(build_id)): self.j.stop_build(jn, int(build_id)) re = delbuild(n, r, build_id, 'aborted') else: re = delbuild(n, r, build_id, 'error') except Exception as e: print e.message re = delbuild(n, r, build_id, 'error') raise gen.Return(re) @gen.coroutine def postbuild(self, jobname, imagename, tag, callback_url): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) try: if self.j.job_exists(jn): j = self.j.get_job_info(jn) build_id = j['nextBuildNumber'] if self.j.get_queue_info() != []: re = postbuild(n, r, imagename, build_id, tag, datetime.now(), 'queue') elif j['queueItem'] != None: re = postbuild(n, r, imagename, build_id, tag, datetime.now(), 'queue') else: self.updateconfig_buildid(jn, imagename, build_id, callback_url) self.j.build_job(jn) re = postbuild(n, r, imagename, build_id, tag, datetime.now(), 'started') else: re = postbuild(n, r, '', '', datetime.now(), 'error') except Exception as e: print e.message re = postbuild(n, r, '', tag, datetime.now(), 'error') raise gen.Return(re) @gen.coroutine def getbuild(self, jobname, build_id): s = {r'/': r'...'} jn = utils.multiple_replace(jobname, s) n, r = self.getjobnames(jn) try: b = self.j.get_build_info(jn, int(build_id)) building = b['building'] duration = b['duration'] dt = self.getlenstr(b['timestamp'], 10) started_at = utils.timestamp_datetime(int(dt)) status = self.getstatus(b['result']) stdout = self.j.get_build_console_output(jn, int(build_id)) bd = build_detail(n, r, build_id, building, started_at, duration, status, stdout) except Exception as e: print e.message bd = build_detail(n, r, build_id, '', '', '', 'error', '') raise gen.Return(bd) def getdocker_sync_config(self): s = '''<?xml version='1.0' encoding='UTF-8'?> <project> <actions/> <description></description> <keepDependencies>false</keepDependencies> <properties> <com.tikal.hudson.plugins.notification.HudsonNotificationProperty plugin="[email protected]"> <endpoints> <com.tikal.hudson.plugins.notification.Endpoint> <protocol>HTTP</protocol> <format>JSON</format> <url>http://10.1.39.60:8080/v1/hook</url> <event>completed</event> <timeout>30000</timeout> <loglines>0</loglines> </com.tikal.hudson.plugins.notification.Endpoint> </endpoints> </com.tikal.hudson.plugins.notification.HudsonNotificationProperty> <com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty plugin="[email protected]"/> <hudson.plugins.heavy__job.HeavyJobProperty plugin="[email protected]"> <weight>1</weight> </hudson.plugins.heavy__job.HeavyJobProperty> <jenkins.model.BuildDiscarderProperty> <strategy class="hudson.tasks.LogRotator"> <daysToKeep>30</daysToKeep> <numToKeep>50</numToKeep> <artifactDaysToKeep>-1</artifactDaysToKeep> <artifactNumToKeep>-1</artifactNumToKeep> </strategy> </jenkins.model.BuildDiscarderProperty> <job-metadata plugin="[email protected]"> <values class="linked-list"> <metadata-tree> <name>job-info</name> <parent class="job-metadata" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-tree> <name>last-saved</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-date> <name>time</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value> <time>1458098001639</time> <timezone>Asia/Shanghai</timezone> </value> <checked>false</checked> </metadata-date> <metadata-tree> <name>user</name> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-string> <name>display-name</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value>admin</value> </metadata-string> <metadata-string> <name>full-name</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value>admin</value> </metadata-string> </children> </metadata-tree> </children> </metadata-tree> </children> </metadata-tree> </values> </job-metadata> </properties> <scm class="hudson.scm.NullSCM"/> <scmCheckoutRetryCount>3</scmCheckoutRetryCount> <canRoam>true</canRoam> <disabled>false</disabled> <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> <triggers/> <concurrentBuild>false</concurrentBuild> <builders> <hudson.tasks.Shell> <command>{docker_login} && docker pull {oldimage} && docker tag --force=true {oldimage} {newimage} && docker push {newimage} </command> </hudson.tasks.Shell> </builders> <publishers/> <buildWrappers> <hudson.plugins.ansicolor.AnsiColorBuildWrapper plugin="[email protected]"> <colorMapName>xterm</colorMapName> </hudson.plugins.ansicolor.AnsiColorBuildWrapper> </buildWrappers> </project>''' return s def getdocker_load_config(self): s = '''<?xml version='1.0' encoding='UTF-8'?> <project> <actions/> <description></description> <keepDependencies>false</keepDependencies> <properties> <com.tikal.hudson.plugins.notification.HudsonNotificationProperty plugin="[email protected]"> <endpoints> <com.tikal.hudson.plugins.notification.Endpoint> <protocol>HTTP</protocol> <format>JSON</format> <url>http://10.1.39.60:8080/v1/hook</url> <event>completed</event> <timeout>30000</timeout> <loglines>0</loglines> </com.tikal.hudson.plugins.notification.Endpoint> </endpoints> </com.tikal.hudson.plugins.notification.HudsonNotificationProperty> <com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty plugin="[email protected]"/> <hudson.plugins.heavy__job.HeavyJobProperty plugin="[email protected]"> <weight>1</weight> </hudson.plugins.heavy__job.HeavyJobProperty> <jenkins.model.BuildDiscarderProperty> <strategy class="hudson.tasks.LogRotator"> <daysToKeep>30</daysToKeep> <numToKeep>50</numToKeep> <artifactDaysToKeep>-1</artifactDaysToKeep> <artifactNumToKeep>-1</artifactNumToKeep> </strategy> </jenkins.model.BuildDiscarderProperty> <job-metadata plugin="[email protected]"> <values class="linked-list"> <metadata-tree> <name>job-info</name> <parent class="job-metadata" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-tree> <name>last-saved</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-date> <name>time</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value> <time>1458097635464</time> <timezone>Asia/Shanghai</timezone> </value> <checked>false</checked> </metadata-date> <metadata-tree> <name>user</name> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-string> <name>display-name</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value>admin</value> </metadata-string> <metadata-string> <name>full-name</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value>admin</value> </metadata-string> </children> </metadata-tree> </children> </metadata-tree> </children> </metadata-tree> </values> </job-metadata> </properties> <scm class="hudson.scm.NullSCM"/> <scmCheckoutRetryCount>3</scmCheckoutRetryCount> <canRoam>true</canRoam> <disabled>false</disabled> <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> <triggers/> <concurrentBuild>false</concurrentBuild> <builders> <hudson.tasks.Shell> <command>{docker_login} && docker import {httpfilename} {imagename} && docker push {imagename} </command> </hudson.tasks.Shell> </builders> <publishers/> <buildWrappers> <hudson.plugins.ansicolor.AnsiColorBuildWrapper plugin="[email protected]"> <colorMapName>xterm</colorMapName> </hudson.plugins.ansicolor.AnsiColorBuildWrapper> </buildWrappers> </project>''' return s def getbasejob_config(self): s = '''<?xml version='1.0' encoding='UTF-8'?> <project> <actions/> <description></description> <keepDependencies>false</keepDependencies> <properties> <com.tikal.hudson.plugins.notification.HudsonNotificationProperty plugin="[email protected]"> <endpoints> <com.tikal.hudson.plugins.notification.Endpoint> <protocol>HTTP</protocol> <format>JSON</format> <url>http://10.1.39.60:8080/v1/hook</url> <event>completed</event> <timeout>30000</timeout> <loglines>0</loglines> </com.tikal.hudson.plugins.notification.Endpoint> </endpoints> </com.tikal.hudson.plugins.notification.HudsonNotificationProperty> <com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty plugin="[email protected]"/> <hudson.plugins.heavy__job.HeavyJobProperty plugin="[email protected]"> <weight>1</weight> </hudson.plugins.heavy__job.HeavyJobProperty> <jenkins.model.BuildDiscarderProperty> <strategy class="hudson.tasks.LogRotator"> <daysToKeep>30</daysToKeep> <numToKeep>50</numToKeep> <artifactDaysToKeep>-1</artifactDaysToKeep> <artifactNumToKeep>-1</artifactNumToKeep> </strategy> </jenkins.model.BuildDiscarderProperty> <job-metadata plugin="[email protected]"> <values class="linked-list"> <metadata-tree> <name>job-info</name> <parent class="job-metadata" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-tree> <name>last-saved</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-date> <name>time</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value> <time>1457958794480</time> <timezone>Asia/Shanghai</timezone> </value> <checked>false</checked> </metadata-date> <metadata-tree> <name>user</name> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <children class="linked-list"> <metadata-string> <name>display-name</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value>admin</value> </metadata-string> <metadata-string> <name>full-name</name> <description></description> <parent class="metadata-tree" reference="../../.."/> <generated>true</generated> <exposedToEnvironment>false</exposedToEnvironment> <value>admin</value> </metadata-string> </children> </metadata-tree> </children> </metadata-tree> </children> </metadata-tree> </values> </job-metadata> </properties> <scm class="hudson.plugins.git.GitSCM" plugin="[email protected]"> <configVersion>2</configVersion> <userRemoteConfigs> <hudson.plugins.git.UserRemoteConfig> <url>https://github.com/zhwenh/dockerfile-jdk-tomcat.git</url> </hudson.plugins.git.UserRemoteConfig> </userRemoteConfigs> <branches> <hudson.plugins.git.BranchSpec> <name>*/master</name> </hudson.plugins.git.BranchSpec> </branches> <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations> <browser class="hudson.plugins.git.browser.GitLab"> <url></url> <version>7.11</version> </browser> <submoduleCfg class="list"/> <extensions/> </scm> <scmCheckoutRetryCount>3</scmCheckoutRetryCount> <canRoam>true</canRoam> <disabled>false</disabled> <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> <triggers/> <concurrentBuild>false</concurrentBuild> <builders> <hudson.tasks.Shell> <command>docker login -u admin -p admin123 -e [email protected] registry.test.com</command> </hudson.tasks.Shell> <com.cloudbees.dockerpublish.DockerBuilder plugin="[email protected]"> <server plugin="[email protected]"> <uri>unix:///var/run/docker.sock</uri> </server> <registry plugin="[email protected]"> <url>http://registry.test.com/v2</url> </registry> <repoName>zhwenh/tomcat</repoName> <noCache>false</noCache> <forcePull>true</forcePull> <dockerfilePath>./Dockerfile</dockerfilePath> <skipBuild>false</skipBuild> <skipDecorate>false</skipDecorate> <repoTag>2.3.1</repoTag> <skipPush>false</skipPush> <createFingerprint>true</createFingerprint> <skipTagLatest>false</skipTagLatest> <buildAdditionalArgs></buildAdditionalArgs> <forceTag>true</forceTag> </com.cloudbees.dockerpublish.DockerBuilder> </builders> <publishers> <hudson.plugins.emailext.ExtendedEmailPublisher plugin="[email protected]"> <recipientList>$DEFAULT_RECIPIENTS</recipientList> <configuredTriggers> <hudson.plugins.emailext.plugins.trigger.FailureTrigger> <email> <recipientList>$DEFAULT_RECIPIENTS</recipientList> <subject>$PROJECT_DEFAULT_SUBJECT</subject> <body>$PROJECT_DEFAULT_CONTENT</body> <recipientProviders> <hudson.plugins.emailext.plugins.recipients.DevelopersRecipientProvider/> </recipientProviders> <attachmentsPattern></attachmentsPattern> <attachBuildLog>false</attachBuildLog> <compressBuildLog>false</compressBuildLog> <replyTo>$PROJECT_DEFAULT_REPLYTO</replyTo> <contentType>project</contentType> </email> </hudson.plugins.emailext.plugins.trigger.FailureTrigger> <hudson.plugins.emailext.plugins.trigger.SuccessTrigger> <email> <recipientList>$DEFAULT_RECIPIENTS</recipientList> <subject>$PROJECT_DEFAULT_SUBJECT</subject> <body>$PROJECT_DEFAULT_CONTENT</body> <recipientProviders> <hudson.plugins.emailext.plugins.recipients.DevelopersRecipientProvider/> </recipientProviders> <attachmentsPattern></attachmentsPattern> <attachBuildLog>false</attachBuildLog> <compressBuildLog>false</compressBuildLog> <replyTo>$PROJECT_DEFAULT_REPLYTO</replyTo> <contentType>project</contentType> </email> </hudson.plugins.emailext.plugins.trigger.SuccessTrigger> </configuredTriggers> <contentType>default</contentType> <defaultSubject>$DEFAULT_SUBJECT</defaultSubject> <defaultContent>$DEFAULT_CONTENT</defaultContent> <attachmentsPattern></attachmentsPattern> <presendScript>$DEFAULT_PRESEND_SCRIPT</presendScript> <attachBuildLog>false</attachBuildLog> <compressBuildLog>false</compressBuildLog> <replyTo></replyTo> <saveOutput>false</saveOutput> <disabled>false</disabled> </hudson.plugins.emailext.ExtendedEmailPublisher> </publishers> <buildWrappers> <hudson.plugins.ansicolor.AnsiColorBuildWrapper plugin="[email protected]"> <colorMapName>xterm</colorMapName> </hudson.plugins.ansicolor.AnsiColorBuildWrapper> </buildWrappers> </project>''' return s @gen.coroutine def createbasejob(self): s = self.getbasejob_config() try: self.j.create_job(config.JENKINS_BASEJOB, s) except Exception as e: print e.message raise gen.Return(False) raise gen.Return(True)
class JenkinsBot(BotPlugin): """Basic Err integration with Jenkins CI""" min_err_version = '1.2.1' # max_err_version = '4.0.3' def get_configuration_template(self): return CONFIG_TEMPLATE def configure(self, configuration): if configuration is not None and configuration != {}: config = dict(chain(CONFIG_TEMPLATE.items(), configuration.items())) else: config = CONFIG_TEMPLATE super(JenkinsBot, self).configure(config) return def check_configuration(self, configuration): self.log.debug(configuration) for c, v in configuration.items(): if c == 'URL': if not validators.url(v): raise ValidationException( 'JENKINS_URL is not a well formed URL') elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']: if len(v) == 0 or not isinstance(v, str): raise ValidationException( "{} is a required string config setting".format(c)) elif c in ['CHATROOMS_NOTIFICATION']: if not isinstance(v, tuple): raise ValidationException( "{} should be of type tuple".format(c)) return def connect_to_jenkins(self): """Connect to a Jenkins instance using configuration.""" self.log.debug('Connecting to Jenkins ({0})'.format( self.config['URL'])) self.jenkins = Jenkins(url=self.config['URL'], username=self.config['USERNAME'], password=self.config['PASSWORD']) return def broadcast(self, mess): """Shortcut to broadcast a message to all elligible chatrooms.""" chatrooms = (self.config['CHATROOMS_NOTIFICATION'] if self.config['CHATROOMS_NOTIFICATION'] else self.bot_config.CHATROOM_PRESENCE) for room in chatrooms: self.send(self.build_identifier(room), mess) return @webhook(r'/jenkins/notification') def handle_notification(self, incoming_request): if not self.config['RECEIVE_NOTIFICATION']: return 'Notification handling is disabled.' self.log.debug(repr(incoming_request)) self.broadcast(self.format_notification(incoming_request)) return @botcmd def jenkins_list(self, mess, args): """List all jobs, optionally filter them using a search term.""" self.connect_to_jenkins() return self.format_jobs([ job for job in self.jenkins.get_jobs(folder_depth=None) if args.lower() in job['fullname'].lower() ]) @botcmd def jenkins_running(self, mess, args): """List all running jobs.""" self.connect_to_jenkins() jobs = [ job for job in self.jenkins.get_jobs() if 'anime' in job['color'] ] return self.format_running_jobs(jobs) @botcmd(split_args_with=None) def jenkins_param(self, mess, args): """List Parameters for a given job.""" if len(args) == 0: return 'What Job would you like the parameters for?' self.connect_to_jenkins() job = self.jenkins.get_job_info(args[0]) if job['actions'][1] != {}: job_param = job['actions'][1]['parameterDefinitions'] elif job['actions'][0] != {}: job_param = job['actions'][0]['parameterDefinitions'] else: job_param = [] return self.format_params(job_param) @botcmd(split_args_with=None) def jenkins_build(self, mess, args): """Build a Jenkins Job with the given parameters Example: !jenkins build test_project FOO:bar """ if len(args) == 0: # No Job name return 'What job would you like to build?' self.connect_to_jenkins() params = self.build_parameters(args[1:]) # Is it a parameterized job ? job = self.jenkins.get_job_info(args[0]) if job['actions'][0] == {} and job['actions'][1] == {}: self.jenkins.build_job(args[0]) else: self.jenkins.build_job(args[0], params) running_job = self.search_job(args[0]) return 'Your job should begin shortly: {0}'.format( self.format_jobs(running_job)) @botcmd(split_args_with=None) def build(self, mess, args): """Shortcut for jenkins_build""" return self.jenkins_build(mess, args) @botcmd def jenkins_unqueue(self, msg, args): """Cancel a queued job. Example !jenkins unqueue foo """ self.connect_to_jenkins() try: queue = self.jenkins.get_queue_info() job = next((job for job in queue if job['task']['name'].lower() == args.lower()), None) if job: self.jenkins.cancel_queue(job['id']) return 'Unqueued job {0}'.format(job['task']['name']) else: return 'Could not find job {0}, but found the following: {1}'.format( args, ', '.join(job['task']['name'] for job in queue)) except JenkinsException as e: return 'Oops, {0}'.format(e) @botcmd(split_args_with=None) def jenkins_createjob(self, mess, args): """Create a Jenkins Job. Example: !jenkins createjob pipeline foo [email protected]:foo/bar.git """ if len(args) < 2: # No Job type or name return 'Oops, I need a type and a name for your new job.' if args[0] not in ('pipeline', 'multibranch'): return 'I\'m sorry, I can only create `pipeline` and \ `multibranch` jobs.' self.connect_to_jenkins() try: if args[0] == 'pipeline': self.jenkins.create_job( args[1], JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2])) elif args[0] == 'multibranch': repository = args[2].rsplit('/', maxsplit=2)[-2:] self.jenkins.create_job( args[1], JENKINS_JOB_TEMPLATE_MULTIBRANCH.format( repo_owner=repository[0].split(':')[-1], repo_name=repository[1].strip('.git'))) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been created: {0}/job/{1}'.format( self.config['URL'], args[1]) @botcmd(split_args_with=None) def jenkins_deletejob(self, mess, args): """Delete a Jenkins Job. Example: !jenkins deletejob foo """ if len(args) < 1: # No job name return 'Oops, I need the name of the job you want me to delete.' self.connect_to_jenkins() try: self.jenkins.delete_job(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been deleted.' @botcmd(split_args_with=None) def jenkins_enablejob(self, mess, args): """Enable a Jenkins Job. Example: !jenkins enablejob foo """ if len(args) < 1: # No job name return 'Oops, I need the name of the job you want me to enable.' self.connect_to_jenkins() try: self.jenkins.enable_job(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been enabled.' @botcmd(split_args_with=None) def jenkins_disablejob(self, mess, args): """Disable a Jenkins Job. Example: !jenkins disablejob foo """ if len(args) < 1: # No job name return 'Oops, I need the name of the job you want me to disable.' self.connect_to_jenkins() try: self.jenkins.disable_job(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been disabled.' @botcmd(split_args_with=None) def jenkins_createnode(self, mess, args): """Create a Jenkins Node with a JNLP Launcher with optionnal labels. Example: !jenkins createnode runner-foo-laptop /home/foo # without labels Example: !jenkins createnode runner-bar-laptop /home/bar linux docker # with labels """ if len(args) < 1: # No node name return 'Oops, I need a name and a working dir for your new node.' self.connect_to_jenkins() try: self.jenkins.create_node(name=args[0], remoteFS=args[1], labels=' '.join(args[2:]), exclusive=True, launcher=LAUNCHER_JNLP) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been created: {0}/computer/{1}'.format( self.config['URL'], args[0]) @botcmd(split_args_with=None) def jenkins_deletenode(self, mess, args): """Delete a Jenkins Node. Example: !jenkins deletenode runner-foo-laptop """ if len(args) < 1: # No node name return 'Oops, I need the name of the node you want me to delete.' self.connect_to_jenkins() try: self.jenkins.delete_node(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been deleted.' @botcmd(split_args_with=None) def jenkins_enablenode(self, mess, args): """Enable a Jenkins Node. Example: !jenkins enablenode runner-foo-laptop """ if len(args) < 1: # No node name return 'Oops, I need the name of the node you want me to enable.' self.connect_to_jenkins() try: self.jenkins.enable_node(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been enabled.' @botcmd(split_args_with=None) def jenkins_disablenode(self, mess, args): """Disable a Jenkins Node. Example: !jenkins disablenode runner-foo-laptop """ if len(args) < 1: # No node name return 'Oops, I need the name of the node you want me to disable.' self.connect_to_jenkins() try: self.jenkins.disable_node(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been disabled.' def search_job(self, search_term): self.log.debug('Querying Jenkins for job "{0}"'.format(search_term)) return [ job for job in self.jenkins.get_jobs(folder_depth=None) if search_term.lower() == job['fullname'].lower() ] def format_running_jobs(self, jobs): if len(jobs) == 0: return 'No running jobs.' jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs] return '\n\n'.join([ '%s (%s)\n%s' % (job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info ]).strip() @staticmethod def format_jobs(jobs): if len(jobs) == 0: return 'No jobs found.' max_length = max([len(job['fullname']) for job in jobs]) return '\n'.join([ '%s (%s)' % (job['fullname'].ljust(max_length), job['url']) for job in jobs ]).strip() @staticmethod def format_params(job): """Format job parameters.""" if len(job) == 0: return 'This job is not parameterized.' PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}} Description: {{p.description}} Default Value: {{p.defaultParameterValue.value}} Parameter Name: {{p.name}} {% endfor %}""") return PARAM_TEMPLATE.render({'params': job}) @staticmethod def format_notification(body): body['fullname'] = body.get('fullname', body['name']) NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \ {{build.status}} for Job {{fullname}} ({{build.full_url}}) {% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \ ({{build.scm.branch}}){% endif %}""") return NOTIFICATION_TEMPLATE.render(body) @staticmethod def build_parameters(params): if len(params) > 0: return { param.split(':')[0]: param.split(':')[1] for param in params } return {'': ''}
class Job(): def __init__(self, job_name): self.j = Jenkins(configuration['jenkinsUrl'], configuration['jenkinsUser'], configuration['jenkinsPass']) self.j._session.verify = False self.job_name = job_name @property def extra_columns(self): return [ 'userId', 'userName', 'currentStage', 'status', 'teardownStatus' ] @property def valid_job_name(self): if '-' in self.job_name: return self.job_name.replace('-', '_') else: return self.job_name @property def parameters_collection(self): return self.get_parameters_names() + self.get_meta_parameters( ) + self.get_test_parameters() + self.extra_columns def get_parameters(self): try: job_info = self.j.get_job_info(name=self.job_name) to_return = dict(job_info['property'][0])['parameterDefinitions'] return to_return except: raise Exception( "Could not find parameters, are you sure this is the name of the job and it is Parameterized?" ) def get_parameters_names(self): names = [] for param in self.get_parameters(): names.append(param['name']) return names def get_parameters_query(self): try: parameters = self.get_parameters() return {parameter['name']: "TEXT" for parameter in parameters} except: raise Exception( f"Something went wrong with receiving parameters from the job {self.job_name}. Are you sure this job exists?" ) def get_meta_parameters(self): return ['number', 'building', 'buildDuration', 'url'] def get_meta_query(self): # number going to be in the column as INT type and not text meta = {} meta['number'] = 'INT' meta['building'] = 'BOOLEAN' meta['buildDuration'] = 'TEXT' meta['url'] = 'TEXT' return meta def get_test_parameters(self): return [ 'testDuration', 'testCount', 'failCount', 'passCount', 'skipCount', "successRate" ] def get_test_query(self): meta = {} keys = self.get_test_parameters() for key in keys: if 'Count' in key or "successRate" in key: meta[key] = 'INT' else: meta[key] = 'TEXT' return meta def get_extra_columns_query(self): meta = {} keys = self.extra_columns for key in keys: meta[key] = 'TEXT' return meta def parameters_query_column(self): columns_query = '\n(' collection = self.get_parameters_query() collection.update(self.get_meta_query()) collection.update(self.get_test_query()) collection.update(self.get_extra_columns_query()) for column, type in collection.items(): columns_query += f"{column} {type} NULL" if not list(collection.items())[-1] == (column, type): columns_query += ',\n' columns_query += ');' print(columns_query) return columns_query def create_table_query(self): ######## #Looking for creating a valid job name because sql query is not ok with dashes ######## query = f'''CREATE TABLE {self.valid_job_name}{self.parameters_query_column()}''' return query
class TaskBuilder: def __init__(self, jenkinsURL): self.j = Jenkins(jenkinsURL) self.jobName = "" #with open("config.xml") as file: with open("./builds/config/job/config.xml") as file: self.templateConfig = file.read() self.template = Template(unicode(self.templateConfig)) def set_new_config(self, **params): self.newConfig = self.template.render(repos=params['repos'], description=params['repos']) def add_build(self, **params): self.set_job_name(**params) self.set_new_config(**params) if self.j.job_exists(self.jobName): self.do_build(**params) else: self.j.create_job(self.jobName, self.newConfig) self.do_build(**params) def do_build(self, **params): self.set_job_name(**params) self.set_new_config(**params) self.j.enable_job(self.jobName) self.j.build_job(self.jobName, {'branch': params['branch'], 'version': params['version'], 'author': params['author'], \ 'styleguide_repo': params['styleguide_repo'], 'styleguide_branch': params['styleguide_branch'], 'sidecar_repo': params['sidecar_repo'], \ 'sidecar_branch': params['sidecar_branch'], 'package_list': params['package_list'], 'upgrade_package': params['upgrade_package'], \ 'latin': params['latin'], 'demo_data': params['demo_data']} ) def set_job_name(self, **params): buildUtil = BuildUtil() self.jobName = buildUtil.get_job_name(repos=params['repos']) def get_build_status(self, jobName): #job_info = self.j.get_job_info(self.jobName) #return build_status color_status = { "aborted": "Aborted", "red": "Failed", "blue": "Succcess" } if jobName == "": print "Have to specify job name" return False else: if self.j.job_exists(jobName): #Job exist in the job list job_info = self.j.get_job_info(jobName) if color_status.has_key(job_info['color']): return color_status[job_info['color']] else: return 'Running' else: print "Have to specify a validate job name" return False def get_job_name(self): return self.jobName def stop_jenkins_job(self, job_url): """ 1. stop one job """ stop_job_url = job_url + 'lastBuild/stop' try: ss = urllib2.urlopen(stop_job_url, None, 30).read() ss.close() except: return '{}' def stop_jenkins_jobs(self, jobName): """ 1. find all the sub job 2. stop all the running sub job 3. stop current job """ if self.j.job_exists(jobName): for x in self.j.get_job_info(jobName)['downstreamProjects']: if self.get_build_status(x['name']) == 'Running': self.stop_jenkins_job(x['url']) self.stop_jenkins_job(self.j.get_job_info(jobName)['url']) else: pass
from jenkins import Jenkins job_settings = { 'DEPLOY_TO': 'feature1.dev.roundme.com', 'FRONTEND_BRANCH': '1.6.1', 'BACKEND_BRANCH': '1.6.1', 'RUN_TEST': False, 'DEPLOY_REPO_BRANCH': 'master', 'NPM_ARGS': 'production', 'GRUNT_ARGS': 'testing', 'DEPLOY_TO_S3': False, 'MIGRATE': False, 'ENV': 'feature' } server = Jenkins('http://234234', username='******', password='******') # serverstring print(server) user = server.get_whoami() print(user) job = server.get_job_config('Roundme.Full.Build') print(job) server.build_job('Roundme.Full.Build', job_settings) last_build_number = server.get_job_info( 'Roundme.Full.Build')['lastCompletedBuild']['number'] build_info = server.get_build_info('Roundme.Full.Build', last_build_number) print(build_info)
class JenkinsBot(BotPlugin): """Basic Err integration with Jenkins CI""" min_err_version = '1.2.1' # max_err_version = '4.0.3' def get_configuration_template(self): return CONFIG_TEMPLATE def configure(self, configuration): if configuration is not None and configuration != {}: config = dict(chain(CONFIG_TEMPLATE.items(), configuration.items())) else: config = CONFIG_TEMPLATE super(JenkinsBot, self).configure(config) return def check_configuration(self, configuration): self.log.debug(configuration) for c, v in configuration.items(): if c == 'URL': if not validators.url(v): raise ValidationException('JENKINS_URL is not a well formed URL') elif c in ['USERNAME', 'PASSWORD', 'RECEIVE_NOTIFICATION']: if len(v) == 0 or not isinstance(v, str): raise ValidationException("{} is a required string config setting".format(c)) elif c in ['CHATROOMS_NOTIFICATION']: if not isinstance(v, tuple): raise ValidationException("{} should be of type tuple".format(c)) return def connect_to_jenkins(self): """Connect to a Jenkins instance using configuration.""" self.log.debug('Connecting to Jenkins ({0})'.format( self.config['URL'])) self.jenkins = Jenkins(url=self.config['URL'], username=self.config['USERNAME'], password=self.config['PASSWORD']) return def broadcast(self, mess): """Shortcut to broadcast a message to all elligible chatrooms.""" chatrooms = (self.config['CHATROOMS_NOTIFICATION'] if self.config['CHATROOMS_NOTIFICATION'] else self.bot_config.CHATROOM_PRESENCE) for room in chatrooms: self.send(self.build_identifier(room), mess) return @webhook(r'/jenkins/notification') def handle_notification(self, incoming_request): if not self.config['RECEIVE_NOTIFICATION']: return 'Notification handling is disabled.' self.log.debug(repr(incoming_request)) self.broadcast(self.format_notification(incoming_request)) return @botcmd def jenkins_list(self, mess, args): """List all jobs, optionally filter them using a search term.""" self.connect_to_jenkins() return self.format_jobs([job for job in self.jenkins.get_jobs(folder_depth=None) if args.lower() in job['fullname'].lower()]) @botcmd def jenkins_running(self, mess, args): """List all running jobs.""" self.connect_to_jenkins() jobs = [job for job in self.jenkins.get_jobs() if 'anime' in job['color']] return self.format_running_jobs(jobs) @botcmd(split_args_with=None) def jenkins_param(self, mess, args): """List Parameters for a given job.""" if len(args) == 0: return 'What Job would you like the parameters for?' self.connect_to_jenkins() job = self.jenkins.get_job_info(args[0]) if job['actions'][1] != {}: job_param = job['actions'][1]['parameterDefinitions'] elif job['actions'][0] != {}: job_param = job['actions'][0]['parameterDefinitions'] else: job_param = [] return self.format_params(job_param) @botcmd(split_args_with=None) def jenkins_build(self, mess, args): """Build a Jenkins Job with the given parameters Example: !jenkins build test_project FOO:bar """ if len(args) == 0: # No Job name return 'What job would you like to build?' self.connect_to_jenkins() params = self.build_parameters(args[1:]) # Is it a parameterized job ? job = self.jenkins.get_job_info(args[0]) if job['actions'][0] == {} and job['actions'][1] == {}: self.jenkins.build_job(args[0]) else: self.jenkins.build_job(args[0], params) running_job = self.search_job(args[0]) return 'Your job should begin shortly: {0}'.format( self.format_jobs(running_job)) @botcmd(split_args_with=None) def build(self, mess, args): """Shortcut for jenkins_build""" return self.jenkins_build(mess, args) @botcmd def jenkins_unqueue(self, msg, args): """Cancel a queued job. Example !jenkins unqueue foo """ self.connect_to_jenkins() try: queue = self.jenkins.get_queue_info() job = next((job for job in queue if job['task']['name'].lower() == args.lower()), None) if job: self.jenkins.cancel_queue(job['id']) return 'Unqueued job {0}'.format(job['task']['name']) else: return 'Could not find job {0}, but found the following: {1}'.format( args, ', '.join(job['task']['name'] for job in queue)) except JenkinsException as e: return 'Oops, {0}'.format(e) @botcmd(split_args_with=None) def jenkins_createjob(self, mess, args): """Create a Jenkins Job. Example: !jenkins createjob pipeline foo [email protected]:foo/bar.git """ if len(args) < 2: # No Job type or name return 'Oops, I need a type and a name for your new job.' if args[0] not in ('pipeline', 'multibranch'): return 'I\'m sorry, I can only create `pipeline` and \ `multibranch` jobs.' self.connect_to_jenkins() try: if args[0] == 'pipeline': self.jenkins.create_job( args[1], JENKINS_JOB_TEMPLATE_PIPELINE.format(repository=args[2])) elif args[0] == 'multibranch': repository = args[2].rsplit('/', maxsplit=2)[-2:] self.jenkins.create_job( args[1], JENKINS_JOB_TEMPLATE_MULTIBRANCH.format( repo_owner=repository[0].split(':')[-1], repo_name=repository[1].strip('.git'))) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been created: {0}/job/{1}'.format( self.config['URL'], args[1]) @botcmd(split_args_with=None) def jenkins_deletejob(self, mess, args): """Delete a Jenkins Job. Example: !jenkins deletejob foo """ if len(args) < 1: # No job name return 'Oops, I need the name of the job you want me to delete.' self.connect_to_jenkins() try: self.jenkins.delete_job(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been deleted.' @botcmd(split_args_with=None) def jenkins_enablejob(self, mess, args): """Enable a Jenkins Job. Example: !jenkins enablejob foo """ if len(args) < 1: # No job name return 'Oops, I need the name of the job you want me to enable.' self.connect_to_jenkins() try: self.jenkins.enable_job(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been enabled.' @botcmd(split_args_with=None) def jenkins_disablejob(self, mess, args): """Disable a Jenkins Job. Example: !jenkins disablejob foo """ if len(args) < 1: # No job name return 'Oops, I need the name of the job you want me to disable.' self.connect_to_jenkins() try: self.jenkins.disable_job(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your job has been disabled.' @botcmd(split_args_with=None) def jenkins_createnode(self, mess, args): """Create a Jenkins Node with a JNLP Launcher with optionnal labels. Example: !jenkins createnode runner-foo-laptop /home/foo # without labels Example: !jenkins createnode runner-bar-laptop /home/bar linux docker # with labels """ if len(args) < 1: # No node name return 'Oops, I need a name and a working dir for your new node.' self.connect_to_jenkins() try: self.jenkins.create_node( name=args[0], remoteFS=args[1], labels=' '.join(args[2:]), exclusive=True, launcher=LAUNCHER_JNLP) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been created: {0}/computer/{1}'.format( self.config['URL'], args[0]) @botcmd(split_args_with=None) def jenkins_deletenode(self, mess, args): """Delete a Jenkins Node. Example: !jenkins deletenode runner-foo-laptop """ if len(args) < 1: # No node name return 'Oops, I need the name of the node you want me to delete.' self.connect_to_jenkins() try: self.jenkins.delete_node(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been deleted.' @botcmd(split_args_with=None) def jenkins_enablenode(self, mess, args): """Enable a Jenkins Node. Example: !jenkins enablenode runner-foo-laptop """ if len(args) < 1: # No node name return 'Oops, I need the name of the node you want me to enable.' self.connect_to_jenkins() try: self.jenkins.enable_node(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been enabled.' @botcmd(split_args_with=None) def jenkins_disablenode(self, mess, args): """Disable a Jenkins Node. Example: !jenkins disablenode runner-foo-laptop """ if len(args) < 1: # No node name return 'Oops, I need the name of the node you want me to disable.' self.connect_to_jenkins() try: self.jenkins.disable_node(args[0]) except JenkinsException as e: return 'Oops, {0}'.format(e) return 'Your node has been disabled.' def search_job(self, search_term): self.log.debug('Querying Jenkins for job "{0}"'.format(search_term)) return [job for job in self.jenkins.get_jobs(folder_depth=None) if search_term.lower() == job['fullname'].lower()] def format_running_jobs(self, jobs): if len(jobs) == 0: return 'No running jobs.' jobs_info = [self.jenkins.get_job_info(job['name']) for job in jobs] return '\n\n'.join(['%s (%s)\n%s' % ( job['name'], job['lastBuild']['url'], job['healthReport'][0]['description']) for job in jobs_info]).strip() @staticmethod def format_jobs(jobs): if len(jobs) == 0: return 'No jobs found.' max_length = max([len(job['fullname']) for job in jobs]) return '\n'.join( ['%s (%s)' % (job['fullname'].ljust(max_length), job['url']) for job in jobs]).strip() @staticmethod def format_params(job): """Format job parameters.""" if len(job) == 0: return 'This job is not parameterized.' PARAM_TEMPLATE = Template("""{% for p in params %}Type: {{p.type}} Description: {{p.description}} Default Value: {{p.defaultParameterValue.value}} Parameter Name: {{p.name}} {% endfor %}""") return PARAM_TEMPLATE.render({'params': job}) @staticmethod def format_notification(body): body['fullname'] = body.get('fullname', body['name']) NOTIFICATION_TEMPLATE = Template("""Build #{{build.number}} \ {{build.status}} for Job {{fullname}} ({{build.full_url}}) {% if build.scm %}Based on {{build.scm.url}}/commit/{{build.scm.commit}} \ ({{build.scm.branch}}){% endif %}""") return NOTIFICATION_TEMPLATE.render(body) @staticmethod def build_parameters(params): if len(params) > 0: return {param.split(':')[0]: param.split(':')[1] for param in params} return {'': ''}
# -*- coding: utf-8 -*- # @Time : 2019-07-26 20:23 # @Author : Eylaine # @File : __init__.py from jenkins import Jenkins from settings import JENKINS_URL as URL from settings import JENKINS_PASSWORD as PASSWORD from settings import JENKINS_USERNAME as USERNAME from settings import JENKINS_JOB_NAME as JOB_NAME """python-jenkins模块的使用和常用方法""" jenkins = Jenkins(URL, USERNAME, PASSWORD) # 获取所有的jobs all_jobs = jenkins.get_all_jobs() # 根据job name获取info,返回json job_info = jenkins.get_job_info(JOB_NAME) # 最后一次build的信息,包含num和url last_build = job_info["lastBuild"] # 最后一次build的number,int类型 NUMBER = last_build["number"] build_info = jenkins.get_build_info(JOB_NAME, NUMBER) info = jenkins.get_info() # 运行日志 console_text = jenkins.get_build_console_output(JOB_NAME, NUMBER)