forked from openlp/openlp
Change the Jenkins script to use the official Jenkins Python API module (python3-jenkins in Debian/Ubuntu and Fedora). Also updated the display a bit and added some helpful messaging. This script now uses your username and your password (or personal token) for authentication instead of a a shared token.
$ python3 scripts/jenkins_script.py -h usage: jenkins_script.py [-h] [-d] [-b] [-n] -u USERNAME -p PASSWORD optional arguments: ... bzr-revno: 2783
This commit is contained in:
commit
c1dc7455db
@ -21,35 +21,35 @@
|
||||
# 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:
|
||||
This script helps to trigger builds of branches. To use it you have to install the python-jenkins module. On Fedora
|
||||
and Ubuntu/Debian, it is available as the ``python3-jenkins`` package::
|
||||
|
||||
pip3 install jenkins-webapi
|
||||
$ sudo dnf/apt install python3-jenkins
|
||||
|
||||
You probably want to create an alias. Add this to your ~/.bashrc file and then logout and login (to apply the alias):
|
||||
To make it easier to run you may want to create a shell script or an alias. To create an alias, add this to your
|
||||
``~/.bashrc`` (or ``~/.zshrc``) file and then log out and log back in again (to apply the alias)::
|
||||
|
||||
alias ci="python3 ./scripts/jenkins_script.py TOKEN"
|
||||
alias ci="python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD"
|
||||
|
||||
You can look up the token in the Branch-01-Pull job configuration or ask in IRC.
|
||||
To create a shell script, create the following file in a location in your ``$PATH`` (I called mine ``ci``)::
|
||||
|
||||
#!/bin/bash
|
||||
python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD
|
||||
|
||||
``USERNAME`` is your Jenkins username, and ``PASSWORD`` is your Jenkins password or personal token.
|
||||
|
||||
An older version of this script used to use a shared TOKEN, but this has been replaced with the username and password.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from optparse import OptionParser
|
||||
from argparse import ArgumentParser
|
||||
from subprocess import Popen, PIPE
|
||||
import warnings
|
||||
|
||||
from requests.exceptions import HTTPError
|
||||
from jenkins import Jenkins
|
||||
|
||||
|
||||
JENKINS_URL = 'https://ci.openlp.io/'
|
||||
REPO_REGEX = r'(.*/+)(~.*)'
|
||||
# Allows us to black list token. So when we change the token, we can display a proper message to the user.
|
||||
OLD_TOKENS = []
|
||||
|
||||
# Disable the InsecureRequestWarning we get from urllib3, because we're not verifying our own self-signed certificate
|
||||
warnings.simplefilter('ignore')
|
||||
|
||||
|
||||
class OpenLPJobs(object):
|
||||
@ -85,13 +85,23 @@ class JenkinsTrigger(object):
|
||||
:param token: The token we need to trigger the build. If you do not have this token, ask in IRC.
|
||||
"""
|
||||
|
||||
def __init__(self, token):
|
||||
def __init__(self, username, password, can_use_colour):
|
||||
"""
|
||||
Create the JenkinsTrigger instance.
|
||||
"""
|
||||
self.token = token
|
||||
self.jobs = {}
|
||||
self.can_use_colour = can_use_colour and not os.name.startswith('nt')
|
||||
self.repo_name = get_repo_name()
|
||||
self.jenkins_instance = Jenkins(JENKINS_URL)
|
||||
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):
|
||||
"""
|
||||
@ -102,15 +112,15 @@ class JenkinsTrigger(object):
|
||||
# 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.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name, 'cause': cause},
|
||||
token=self.token)
|
||||
self.fetch_jobs()
|
||||
self.server.build_job(OpenLPJobs.Branch_Pull, {'BRANCH_NAME': self.repo_name, 'cause': cause})
|
||||
|
||||
def print_output(self):
|
||||
"""
|
||||
Print the status information of the build triggered.
|
||||
"""
|
||||
print('Add this to your merge proposal:')
|
||||
print('--------------------------------')
|
||||
print('-' * 80)
|
||||
bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE)
|
||||
raw_output, error = bzr.communicate()
|
||||
revno = raw_output.decode().strip()
|
||||
@ -118,7 +128,10 @@ class JenkinsTrigger(object):
|
||||
|
||||
for job in OpenLPJobs.Jobs:
|
||||
if not self.__print_build_info(job):
|
||||
print('Stopping after failure')
|
||||
if self.current_build:
|
||||
print('Stopping after failure, see {}console for more details'.format(self.current_build['url']))
|
||||
else:
|
||||
print('Stopping after failure')
|
||||
break
|
||||
|
||||
def open_browser(self):
|
||||
@ -129,6 +142,20 @@ class JenkinsTrigger(object):
|
||||
# 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
|
||||
while queue_info and tries < 50:
|
||||
tries += 1
|
||||
time.sleep(0.5)
|
||||
queue_info = self.server.get_queue_info()
|
||||
if tries >= 50:
|
||||
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``
|
||||
@ -136,21 +163,24 @@ class JenkinsTrigger(object):
|
||||
: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)
|
||||
is_success = False
|
||||
job = self.jenkins_instance.job(job_name)
|
||||
while job.info['inQueue']:
|
||||
time.sleep(1)
|
||||
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)
|
||||
is_success = True
|
||||
else:
|
||||
# Make 'FAILURE' red.
|
||||
result_string = '%s%s%s' % (Colour.RED_START, build.info['result'], Colour.RED_END)
|
||||
url = build.info['url']
|
||||
print('[%s] %s' % (result_string, url))
|
||||
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
|
||||
|
||||
|
||||
@ -186,36 +216,29 @@ def get_repo_name():
|
||||
|
||||
|
||||
def main():
|
||||
usage = 'Usage: python %prog TOKEN [options]'
|
||||
"""
|
||||
Run the script
|
||||
"""
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('-d', '--disable-output', action='store_true', default=False, help='Disable output')
|
||||
parser.add_argument('-b', '--open-browser', action='store_true', default=False,
|
||||
help='Opens the jenkins page in your browser')
|
||||
parser.add_argument('-n', '--no-colour', action='store_true', default=False,
|
||||
help='Disable coloured output (always disabled on Windows)')
|
||||
parser.add_argument('-u', '--username', required=True, help='Your Jenkins username')
|
||||
parser.add_argument('-p', '--password', required=True, help='Your Jenkins password or personal token')
|
||||
args = parser.parse_args()
|
||||
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option('-d', '--disable-output', dest='enable_output', action='store_false', default=True,
|
||||
help='Disable output.')
|
||||
parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False,
|
||||
help='Opens the jenkins page in your browser.')
|
||||
options, args = parser.parse_args(sys.argv)
|
||||
|
||||
if len(args) == 2:
|
||||
if not get_repo_name():
|
||||
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
|
||||
return
|
||||
token = args[-1]
|
||||
if token in OLD_TOKENS:
|
||||
print('Your token is not valid anymore. Get the most recent one.')
|
||||
return
|
||||
jenkins_trigger = JenkinsTrigger(token)
|
||||
try:
|
||||
jenkins_trigger.trigger_build()
|
||||
except HTTPError:
|
||||
print('Wrong token.')
|
||||
return
|
||||
# Open the browser before printing the output.
|
||||
if options.open_browser:
|
||||
jenkins_trigger.open_browser()
|
||||
if options.enable_output:
|
||||
jenkins_trigger.print_output()
|
||||
else:
|
||||
parser.print_help()
|
||||
if not get_repo_name():
|
||||
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
|
||||
return
|
||||
jenkins_trigger = JenkinsTrigger(args.username, args.password, not args.no_colour)
|
||||
jenkins_trigger.trigger_build()
|
||||
# Open the browser before printing the output.
|
||||
if args.open_browser:
|
||||
jenkins_trigger.open_browser()
|
||||
if not args.disable_output:
|
||||
jenkins_trigger.print_output()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
Loading…
Reference in New Issue
Block a user