diff --git a/jenkins.py b/jenkins.py new file mode 100644 index 0000000..20a0a79 --- /dev/null +++ b/jenkins.py @@ -0,0 +1,148 @@ +import prof +import os +import webbrowser +import jenkinsapi +from jenkinsapi.jenkins import Jenkins + +jenkins_url = "http://localhost:8080" +username = None +password = None + +failing = [] +passing = [] + +def _open_job_url(url): + savout = os.dup(1) + saverr = os.dup(2) + os.close(1) + os.close(2) + os.open(os.devnull, os.O_RDWR) + try: + webbrowser.open(url, new=2) + finally: + os.dup2(savout, 1) + os.dup2(saverr, 2) + +def _list_jobs(j): + if len(j.keys()) == 0: + prof.cons_show("Jenkins: No jobs available") + else: + prof.cons_show("") + prof.cons_show("Jenkins jobs:") + for name, job in j.get_jobs(): + if job.is_queued(): + prof.cons_show(" " + name + ", QUEUED") + elif job.is_running(): + prof.cons_show(" " + name + ", RUNNING") + else: + build = job.get_last_build_or_none() + if build: + prof.cons_show(" " + name + " #" + str(build.get_number()) + ", " + build.get_status()) + else: + prof.cons_show(" " + name + ", no builds") + prof.cons_show("") + +def _show_job(j, jobname): + if not jobname: + prof.cons_show("Usage /jenkins show [name]") + else: + if j.has_job(jobname): + prof.cons_show("") + job = j.get_job(jobname) + prof.cons_show(jobname + " details:"); + + desc = job.get_description() + if desc: + prof.cons_show (" Description : " + desc) + + if job.is_queued(): + prof.cons_show (" Status : Queued") + elif job.is_running(): + prof.cons_show (" Status : Running") + else: + build = job.get_last_build_or_none() + if build: + prof.cons_show (" Last build : #" + str(build.get_number())) + prof.cons_show (" Status : " + build.get_status()) + else: + prof.cons_show (" Last build : No builds") + + prof.cons_show (" Trigger : " + job.get_build_triggerurl()) + prof.cons_show("") + else: + prof.cons_show("No such job " + jobname) + +def _build_job(j, jobname): + if not jobname: + prof.cons_show("Usage /jenkins build [name]") + else: + if j.has_job(jobname): + job = j.get_job(jobname) + try: + job.invoke(invoke_pre_check_delay=1) + except Exception, e: + prof.cons_show("Failed to trigger build: " + str(e)) + else: + prof.cons_show("No such job " + jobname) + +def _open_job(j, jobname): + if not jobname: + prof.cons_show("Usage /jenkins open [name]") + else: + if j.has_job(jobname): + _open_job_url(jenkins_url + "/job/" + jobname) + else: + prof.cons_show("No such job " + jobname) + +def _cmd_jenkins(cmd, jobname=None): + try: + j = Jenkins(jenkins_url, username, password) + except Exception: + prof.cons_show("Jenkins down") + else: + if cmd == "jobs": + _list_jobs(j) + elif cmd == "show": + _show_job(j, jobname) + elif cmd == "build": + _build_job(j, jobname) + elif cmd == "open": + _open_job(j, jobname) + else: + prof.cons_show("Usage: /jenkins jobs|show|build|open [name]") + +def _process_job(name, job): + global failing + global passing + + if not job.is_queued_or_running(): + build = job.get_last_build_or_none() + if build: + if build.get_status() == "FAILURE": + if not name in failing: + prof.cons_show("Jenkins job: " + name + " #" + str(build.get_number()) + " BROKEN") + prof.notify(name + " broken", 5000, "Build failed") + failing.append(name) + if name in passing: + passing.remove(name) + else: + if name in failing: + prof.cons_show("Jenkins job: " + name + " #" + str(build.get_number()) + " FIXED") + prof.notify(name + " fixed", 5000, "Build fixed") + failing.remove(name) + if not name in passing: + passing.append(name) + +def _poll_jobs(): + try: + j = Jenkins(jenkins_url, username, password) + except Exception: + prof.cons_show("Jenkins down") + else: + for name, job in j.get_jobs(): + _process_job(name, job) + +def prof_init(version, status): + prof.register_timed(_poll_jobs, 30) + prof.register_command("/jenkins", 1, 2, "/jenkins jobs|show|build|open [name]", "Do jenkins stuff.", "Do jenkins stuff.", + _cmd_jenkins)