21
21
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
22
22
###############################################################################
24
This script helps to trigger builds of branches. To use it you have to install the jenkins-webapi package:
26
pip3 install jenkins-webapi
28
You probably want to create an alias. Add this to your ~/.bashrc file and then logout and login (to apply the alias):
30
alias ci="python3 ./scripts/jenkins_script.py TOKEN"
32
You can look up the token in the Branch-01-Pull job configuration or ask in IRC.
24
This script helps to trigger builds of branches. To use it you have to install the python-jenkins module. On Fedora
25
and Ubuntu/Debian, it is available as the ``python3-jenkins`` package::
27
$ sudo dnf/apt install python3-jenkins
29
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
30
``~/.bashrc`` (or ``~/.zshrc``) file and then log out and log back in again (to apply the alias)::
32
alias ci="python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD"
34
To create a shell script, create the following file in a location in your ``$PATH`` (I called mine ``ci``)::
37
python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD
39
``USERNAME`` is your Jenkins username, and ``PASSWORD`` is your Jenkins password or personal token.
41
An older version of this script used to use a shared TOKEN, but this has been replaced with the username and password.
38
from optparse import OptionParser
46
from argparse import ArgumentParser
39
47
from subprocess import Popen, PIPE
42
from requests.exceptions import HTTPError
43
49
from jenkins import Jenkins
46
51
JENKINS_URL = 'https://ci.openlp.io/'
47
52
REPO_REGEX = r'(.*/+)(~.*)'
48
# Allows us to black list token. So when we change the token, we can display a proper message to the user.
51
# Disable the InsecureRequestWarning we get from urllib3, because we're not verifying our own self-signed certificate
52
warnings.simplefilter('ignore')
55
55
class OpenLPJobs(object):
85
85
:param token: The token we need to trigger the build. If you do not have this token, ask in IRC.
88
def __init__(self, token):
88
def __init__(self, username, password, can_use_colour):
90
90
Create the JenkinsTrigger instance.
93
self.can_use_colour = can_use_colour and not os.name.startswith('nt')
93
94
self.repo_name = get_repo_name()
94
self.jenkins_instance = Jenkins(JENKINS_URL)
95
self.server = Jenkins(JENKINS_URL, username=username, password=password)
99
Get the job info for all the jobs
101
for job_name in OpenLPJobs.Jobs:
102
job_info = self.server.get_job_info(job_name)
103
self.jobs[job_name] = job_info
104
self.jobs[job_name]['nextBuildUrl'] = '{url}{nextBuildNumber}/'.format(**job_info)
96
106
def trigger_build(self):
102
112
# We just want the name (not the email).
103
113
name = ' '.join(raw_output.decode().split()[:-1])
104
114
cause = 'Build triggered by %s (%s)' % (name, self.repo_name)
105
self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name, 'cause': cause},
116
self.server.build_job(OpenLPJobs.Branch_Pull, {'BRANCH_NAME': self.repo_name, 'cause': cause})
108
118
def print_output(self):
110
120
Print the status information of the build triggered.
112
122
print('Add this to your merge proposal:')
113
print('--------------------------------')
114
124
bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE)
115
125
raw_output, error = bzr.communicate()
116
126
revno = raw_output.decode().strip()
130
143
Popen(('xdg-open', url), stderr=PIPE)
145
def _get_build_info(self, job_name, build_number):
147
Get the build info from the server. This method will check the queue and wait for the build.
149
queue_info = self.server.get_queue_info()
151
while queue_info and tries < 50:
154
queue_info = self.server.get_queue_info()
156
raise Exception('Build has not started yet, it may be stuck in the queue.')
157
return self.server.get_build_info(job_name, build_number)
132
159
def __print_build_info(self, job_name):
134
161
This helper method prints the job information of the given ``job_name``
136
163
:param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class
137
164
variables from the :class:`OpenLPJobs` class.
166
job = self.jobs[job_name]
167
print('{:<70} [WAITING]'.format(job['nextBuildUrl']), end='', flush=True)
168
self.current_build = self._get_build_info(job_name, job['nextBuildNumber'])
169
print('\b\b\b\b\b\b\b\b\b[RUNNING]', end='', flush=True)
139
170
is_success = False
140
job = self.jenkins_instance.job(job_name)
141
while job.info['inQueue']:
143
build = job.last_build
145
if build.info['result'] == 'SUCCESS':
146
# Make 'SUCCESS' green.
147
result_string = '%s%s%s' % (Colour.GREEN_START, build.info['result'], Colour.GREEN_END)
150
# Make 'FAILURE' red.
151
result_string = '%s%s%s' % (Colour.RED_START, build.info['result'], Colour.RED_END)
152
url = build.info['url']
153
print('[%s] %s' % (result_string, url))
171
while self.current_build['building'] is True:
173
self.current_build = self.server.get_build_info(job_name, job['nextBuildNumber'])
174
result_string = self.current_build['result']
175
is_success = result_string == 'SUCCESS'
176
if self.can_use_colour:
178
# Make 'SUCCESS' green.
179
result_string = '{}{}{}'.format(Colour.GREEN_START, result_string, Colour.GREEN_END)
181
# Make 'FAILURE' red.
182
result_string = '{}{}{}'.format(Colour.RED_START, result_string, Colour.RED_END)
183
print('\b\b\b\b\b\b\b\b\b[{:>7}]'.format(result_string))
154
184
return is_success
189
usage = 'Usage: python %prog TOKEN [options]'
191
parser = OptionParser(usage=usage)
192
parser.add_option('-d', '--disable-output', dest='enable_output', action='store_false', default=True,
193
help='Disable output.')
194
parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False,
195
help='Opens the jenkins page in your browser.')
196
options, args = parser.parse_args(sys.argv)
199
if not get_repo_name():
200
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
203
if token in OLD_TOKENS:
204
print('Your token is not valid anymore. Get the most recent one.')
206
jenkins_trigger = JenkinsTrigger(token)
208
jenkins_trigger.trigger_build()
210
print('Wrong token.')
212
# Open the browser before printing the output.
213
if options.open_browser:
214
jenkins_trigger.open_browser()
215
if options.enable_output:
216
jenkins_trigger.print_output()
222
parser = ArgumentParser()
223
parser.add_argument('-d', '--disable-output', action='store_true', default=False, help='Disable output')
224
parser.add_argument('-b', '--open-browser', action='store_true', default=False,
225
help='Opens the jenkins page in your browser')
226
parser.add_argument('-n', '--no-colour', action='store_true', default=False,
227
help='Disable coloured output (always disabled on Windows)')
228
parser.add_argument('-u', '--username', required=True, help='Your Jenkins username')
229
parser.add_argument('-p', '--password', required=True, help='Your Jenkins password or personal token')
230
args = parser.parse_args()
232
if not get_repo_name():
233
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
235
jenkins_trigger = JenkinsTrigger(args.username, args.password, not args.no_colour)
236
jenkins_trigger.trigger_build()
237
# Open the browser before printing the output.
238
if args.open_browser:
239
jenkins_trigger.open_browser()
240
if not args.disable_output:
241
jenkins_trigger.print_output()
221
244
if __name__ == '__main__':