openlp/scripts/jenkins_script.py

222 lines
8.3 KiB
Python
Raw Normal View History

2014-03-31 16:08:42 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2015-01-18 13:39:21 +00:00
# Copyright (c) 2008-2015 OpenLP Developers #
2014-03-31 16:08:42 +00:00
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
This script helps to trigger builds of branches. To use it you have to install the jenkins-webapi package:
2014-03-31 17:01:09 +00:00
pip3 install jenkins-webapi
2014-03-31 16:08:42 +00:00
2014-03-31 16:40:36 +00:00
You probably want to create an alias. Add this to your ~/.bashrc file and then logout and login (to apply the alias):
2014-03-31 16:08:42 +00:00
2014-03-31 17:30:14 +00:00
alias ci="python3 ./scripts/jenkins_script.py TOKEN"
2014-03-31 16:08:42 +00:00
2014-03-31 16:40:36 +00:00
You can look up the token in the Branch-01-Pull job configuration or ask in IRC.
2014-03-31 16:08:42 +00:00
"""
2014-04-03 19:58:03 +00:00
import re
2014-03-31 16:08:42 +00:00
import sys
import time
2015-03-02 19:18:14 +00:00
from optparse import OptionParser
from subprocess import Popen, PIPE
import warnings
2014-03-31 16:08:42 +00:00
2015-03-02 19:18:14 +00:00
from requests.exceptions import HTTPError
2014-03-31 16:08:42 +00:00
from jenkins import Jenkins
JENKINS_URL = 'https://ci.openlp.io/'
2014-04-05 09:42:23 +00:00
REPO_REGEX = r'(.*/+)(~.*)'
2014-04-12 16:52:29 +00:00
# Allows us to black list token. So when we change the token, we can display a proper message to the user.
OLD_TOKENS = []
2014-03-31 16:08:42 +00:00
2015-03-02 19:18:14 +00:00
# Disable the InsecureRequestWarning we get from urllib3, because we're not verifying our own self-signed certificate
warnings.simplefilter('ignore')
2014-03-31 16:08:42 +00:00
class OpenLPJobs(object):
"""
This class holds any jobs we have on jenkins and we actually need in this script.
"""
Branch_Pull = 'Branch-01-Pull'
Branch_Functional = 'Branch-02-Functional-Tests'
Branch_Interface = 'Branch-03-Interface-Tests'
2014-07-14 07:21:36 +00:00
Branch_Windows_Functional = 'Branch-04a-Windows_Functional_Tests'
Branch_Windows_Interface = 'Branch-04b-Windows_Interface_Tests'
2014-04-14 19:01:48 +00:00
Branch_PEP = 'Branch-05a-Code_Analysis'
2014-04-14 19:16:46 +00:00
Branch_Coverage = 'Branch-05b-Test_Coverage'
2014-03-31 16:08:42 +00:00
2014-07-14 07:27:38 +00:00
Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows_Functional, Branch_Windows_Interface,
Branch_PEP, Branch_Coverage]
2014-03-31 16:08:42 +00:00
class Colour(object):
"""
This class holds values which can be used to print coloured text.
"""
RED_START = '\033[1;31m'
RED_END = '\033[1;m'
GREEN_START = '\033[1;32m'
GREEN_END = '\033[1;m'
2014-03-31 16:08:42 +00:00
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.
"""
2014-03-31 16:08:42 +00:00
def __init__(self, token):
"""
Create the JenkinsTrigger instance.
"""
self.token = token
self.repo_name = get_repo_name()
self.jenkins_instance = Jenkins(JENKINS_URL, verify=False)
2014-03-31 16:08:42 +00:00
def trigger_build(self):
"""
Ask our jenkins server to build the "Branch-01-Pull" job.
"""
2014-04-12 16:52:29 +00:00
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)
2015-03-02 19:18:14 +00:00
self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name, 'cause': cause},
token=self.token)
2014-03-31 16:08:42 +00:00
def print_output(self):
"""
2014-10-13 10:03:53 +00:00
Print the status information of the build triggered.
2014-03-31 16:08:42 +00:00
"""
2014-04-12 16:52:29 +00:00
print('Add this to your merge proposal:')
print('--------------------------------')
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))
2014-03-31 16:08:42 +00:00
for job in OpenLPJobs.Jobs:
2014-07-17 21:55:54 +00:00
if not self.__print_build_info(job):
print('Stopping after failure')
break
2014-03-31 16:08:42 +00:00
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 __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.
"""
2014-07-17 21:55:54 +00:00
is_success = False
2014-03-31 16:08:42 +00:00
job = self.jenkins_instance.job(job_name)
while job.info['inQueue']:
2014-04-03 19:46:12 +00:00
time.sleep(1)
2014-03-31 16:08:42 +00:00
build = job.last_build
build.wait()
if build.info['result'] == 'SUCCESS':
# Make 'SUCCESS' green.
result_string = '%s%s%s' % (Colour.GREEN_START, build.info['result'], Colour.GREEN_END)
2014-07-17 21:55:54 +00:00
is_success = True
else:
# Make 'FAILURE' red.
result_string = '%s%s%s' % (Colour.RED_START, build.info['result'], Colour.RED_END)
2014-03-31 16:08:42 +00:00
url = build.info['url']
print('[%s] %s' % (result_string, url))
2014-07-17 21:55:54 +00:00
return is_success
2014-03-31 16:08:42 +00:00
def get_repo_name():
"""
2014-04-19 05:09:54 +00:00
This returns the name of branch of the working directory. For example it returns *lp:~googol/openlp/render*.
2014-03-31 16:08:42 +00:00
"""
# Run the bzr command.
bzr = Popen(('bzr', 'info'), stdout=PIPE, stderr=PIPE)
raw_output, error = bzr.communicate()
# Detect any errors
if error:
print('This is not a branch.')
return
# Clean the output.
raw_output = raw_output.decode()
output_list = list(map(str.strip, raw_output.split('\n')))
# Determine the branch's name
repo_name = ''
for line in output_list:
# Check if it is remote branch.
if 'push branch' in line:
2014-04-03 19:58:03 +00:00
match = re.match(REPO_REGEX, line)
if match:
repo_name = 'lp:%s' % match.group(2)
break
2014-03-31 16:08:42 +00:00
elif 'checkout of branch' in line:
2014-04-03 19:58:03 +00:00
match = re.match(REPO_REGEX, line)
if match:
repo_name = 'lp:%s' % match.group(2)
break
2014-04-12 16:52:29 +00:00
return repo_name.strip('/')
2014-03-31 16:08:42 +00:00
def main():
usage = 'Usage: python %prog TOKEN [options]'
parser = OptionParser(usage=usage)
2014-04-12 16:52:29 +00:00
parser.add_option('-d', '--disable-output', dest='enable_output', action='store_false', default=True,
2014-03-31 16:37:43 +00:00
help='Disable output.')
2014-04-12 16:52:29 +00:00
parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False,
2014-03-31 16:08:42 +00:00
help='Opens the jenkins page in your browser.')
options, args = parser.parse_args(sys.argv)
if len(args) == 2:
if not get_repo_name():
2014-04-12 16:52:29 +00:00
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
2014-03-31 16:08:42 +00:00
return
token = args[-1]
2014-04-12 16:52:29 +00:00
if token in OLD_TOKENS:
print('Your token is not valid anymore. Get the most recent one.')
return
2014-03-31 16:08:42 +00:00
jenkins_trigger = JenkinsTrigger(token)
2014-03-31 16:37:43 +00:00
try:
jenkins_trigger.trigger_build()
2014-04-19 05:09:54 +00:00
except HTTPError:
2014-04-12 16:52:29 +00:00
print('Wrong token.')
2014-03-31 16:37:43 +00:00
return
2014-03-31 16:08:42 +00:00
# Open the browser before printing the output.
if options.open_browser:
jenkins_trigger.open_browser()
if options.enable_output:
jenkins_trigger.print_output()
else:
2014-03-31 16:37:43 +00:00
parser.print_help()
2014-03-31 16:08:42 +00:00
if __name__ == '__main__':
main()