openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #23141
[Merge] lp:~googol/openlp/jenkins-script into lp:openlp
Andreas Preikschat has proposed merging lp:~googol/openlp/jenkins-script into lp:openlp.
Requested reviews:
Raoul Snyman (raoul-snyman)
Tim Bentley (trb143)
For more details, see:
https://code.launchpad.net/~googol/openlp/jenkins-script/+merge/215950
Hello,
+Print repository name and revision number when using script (especially the revno is interesting for devs)
+Tell jenkins who triggered the build
+Added a blacklist for outdated tokens
+Use colours to indicate success/failure
+fixed job names
The failure of the code analyse is fixed in the duplicate speed branch.
lp:~googol/openlp/jenkins-script (revision 2366)
[SUCCESS] http://ci.openlp.org/job/Branch-01-Pull/338/
[SUCCESS] http://ci.openlp.org/job/Branch-02-Functional-Tests/295/
[SUCCESS] http://ci.openlp.org/job/Branch-03-Interface-Tests/243/
[SUCCESS] http://ci.openlp.org/job/Branch-04-Windows_Tests/205/
[FAILURE] http://ci.openlp.org/job/Branch-05a-Code_Analysis/139/
[SUCCESS] http://ci.openlp.org/job/Branch-05b-Test_Coverage/14/
--
https://code.launchpad.net/~googol/openlp/jenkins-script/+merge/215950
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'scripts/jenkins_script.py'
--- scripts/jenkins_script.py 2014-03-31 18:10:14 +0000
+++ scripts/jenkins_script.py 2014-04-15 20:38:31 +0000
@@ -40,6 +40,7 @@
"""
from optparse import OptionParser
+import re
from requests.exceptions import HTTPError
from subprocess import Popen, PIPE
import sys
@@ -49,6 +50,9 @@
JENKINS_URL = 'http://ci.openlp.org/'
+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 = []
class OpenLPJobs(object):
@@ -59,9 +63,20 @@
Branch_Functional = 'Branch-02-Functional-Tests'
Branch_Interface = 'Branch-03-Interface-Tests'
Branch_Windows = 'Branch-04-Windows_Tests'
- Branch_PEP = 'Branch-05-Code-Analysis'
-
- Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP]
+ Branch_PEP = 'Branch-05a-Code_Analysis'
+ Branch_Coverage = 'Branch-05b-Test_Coverage'
+
+ Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP, Branch_Coverage]
+
+
+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'
class JenkinsTrigger(object):
@@ -79,14 +94,25 @@
"""
Ask our jenkins server to build the "Branch-01-Pull" job.
"""
- self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name}, token=self.token)
+ 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.jenkins_instance.job(OpenLPJobs.Branch_Pull).build(
+ {'BRANCH_NAME': self.repo_name, 'cause': cause}, token=self.token)
def print_output(self):
"""
Print the status information of the build tirggered.
"""
- print("Add this to your merge proposal:")
- print("--------------------------------")
+ 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))
+
for job in OpenLPJobs.Jobs:
self.__print_build_info(job)
@@ -107,17 +133,17 @@
"""
job = self.jenkins_instance.job(job_name)
while job.info['inQueue']:
- # Give other processes the possibility to take over. Like Thread.yield().
- time.sleep(0)
+ time.sleep(1)
build = job.last_build
build.wait()
- result_string = build.info['result']
+ if build.info['result'] == 'SUCCESS':
+ # Make 'SUCCESS' green.
+ result_string = '%s%s%s' % (Colour.GREEN_START, build.info['result'], Colour.GREEN_END)
+ 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))
- # On failure open the browser.
- #if result_string == "FAILURE":
- # url += 'console'
- # Popen(('xdg-open', url), stderr=PIPE)
def get_repo_name():
@@ -139,46 +165,41 @@
for line in output_list:
# Check if it is remote branch.
if 'push branch' in line:
- repo_name = line.replace('push branch: bzr+ssh://bazaar.launchpad.net/', 'lp:')
- break
+ match = re.match(REPO_REGEX, line)
+ if match:
+ repo_name = 'lp:%s' % match.group(2)
+ break
elif 'checkout of branch' in line:
- repo_name = line.replace('checkout of branch: bzr+ssh://bazaar.launchpad.net/', 'lp:')
- break
- repo_name = repo_name.strip('/')
-
- # Did we find the branch name?
- if not repo_name:
- for line in output_list:
- # Check if the branch was pushed.
- if 'Shared repository with trees (format: 2a)' in line:
- print('Not a branch. cd to a branch.')
- return
- print('Not a branch. Have you pushed it to launchpad?')
- return
- return repo_name
+ match = re.match(REPO_REGEX, line)
+ if match:
+ repo_name = 'lp:%s' % match.group(2)
+ break
+ return repo_name.strip('/')
def main():
usage = 'Usage: python %prog TOKEN [options]'
parser = OptionParser(usage=usage)
- parser.add_option('-d', '--disable-output', dest='enable_output', action="store_false", default=True,
+ 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,
+ parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False,
help='Opens the jenkins page in your browser.')
- #parser.add_option('-e', '--open-browser-on-error', dest='open_browser_on_error', action="store_true",
- # default=False, help='Opens the jenkins page in your browser in case a test fails.')
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 as e:
- print("Wrong token.")
+ print('Wrong token.')
return
# Open the browser before printing the output.
if options.open_browser:
=== modified file 'tests/functional/openlp_core_lib/test_image_manager.py'
--- tests/functional/openlp_core_lib/test_image_manager.py 2014-03-14 22:08:44 +0000
+++ tests/functional/openlp_core_lib/test_image_manager.py 2014-04-15 20:38:31 +0000
@@ -30,12 +30,16 @@
Package to test the openlp.core.ui package.
"""
import os
+import time
+from threading import Lock
from unittest import TestCase
from PyQt4 import QtGui
from openlp.core.common import Registry
from openlp.core.lib import ImageManager, ScreenList
+from openlp.core.lib.imagemanager import Priority
+from tests.functional import patch
from tests.helpers.testmixin import TestMixin
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
@@ -51,6 +55,8 @@
self.get_application()
ScreenList.create(self.app.desktop())
self.image_manager = ImageManager()
+ self.lock = Lock()
+ self.sleep_time = 0.1
def tearDown(self):
"""
@@ -82,3 +88,87 @@
with self.assertRaises(KeyError) as context:
self.image_manager.get_image(TEST_PATH, 'church1.jpg')
self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing image')
+
+ def process_cache_test(self):
+ """
+ Test the process_cache method
+ """
+ with patch('openlp.core.lib.imagemanager.resize_image') as mocked_resize_image, \
+ patch('openlp.core.lib.imagemanager.image_to_byte') as mocked_image_to_byte:
+ # GIVEN: Mocked functions
+ mocked_resize_image.side_effect = self.mocked_resize_image
+ mocked_image_to_byte.side_effect = self.mocked_image_to_byte
+ image1 = 'church.jpg'
+ image2 = 'church2.jpg'
+ image3 = 'church3.jpg'
+ image4 = 'church4.jpg'
+
+ # WHEN: Add the images. Then get the lock (=queue can not be processed).
+ self.lock.acquire()
+ self.image_manager.add_image(TEST_PATH, image1, None)
+ self.image_manager.add_image(TEST_PATH, image2, None)
+
+ # THEN: All images have been added to the queue, and only the first image is not be in the list anymore, but
+ # is being processed (see mocked methods/functions).
+ # Note: Priority.Normal means, that the resize_image() was not completed yet (because afterwards the #
+ # priority is adjusted to Priority.Lowest).
+ self.assertEqual(self.get_image_priority(image1), Priority.Normal,
+ "image1's priority should be 'Priority.Normal'")
+ self.assertEqual(self.get_image_priority(image2), Priority.Normal,
+ "image2's priority should be 'Priority.Normal'")
+
+ # WHEN: Add more images.
+ self.image_manager.add_image(TEST_PATH, image3, None)
+ self.image_manager.add_image(TEST_PATH, image4, None)
+ # Allow the queue to process.
+ self.lock.release()
+ # Request some "data".
+ image_bytes = self.image_manager.get_image_bytes(TEST_PATH, image4)
+ image_object = self.image_manager.get_image(TEST_PATH, image3)
+ # Now the mocked methods/functions do not have to sleep anymore.
+ self.sleep_time = 0
+ # Wait for the queue to finish.
+ while not self.image_manager._conversion_queue.empty():
+ time.sleep(0.1)
+ # Because empty() is not reliable, wait a litte; just to make sure.
+ time.sleep(0.1)
+ # THEN: The images' priority reflect how they were processed.
+ self.assertEqual(self.image_manager._conversion_queue.qsize(), 0, "The queue should be empty.")
+ self.assertEqual(self.get_image_priority(image1), Priority.Lowest,
+ "The image should have not been requested (=Lowest)")
+ self.assertEqual(self.get_image_priority(image2), Priority.Lowest,
+ "The image should have not been requested (=Lowest)")
+ self.assertEqual(self.get_image_priority(image3), Priority.Low,
+ "Only the QImage should have been requested (=Low).")
+ self.assertEqual(self.get_image_priority(image4), Priority.Urgent,
+ "The image bytes should have been requested (=Urgent).")
+
+ def get_image_priority(self, image):
+ """
+ This is a help method to get the priority of the given image out of the image_manager's cache.
+
+ NOTE: This requires, that the image has been added to the image manager using the *TEST_PATH*.
+
+ :param image: The name of the image. E. g. ``image1``
+ """
+ return self.image_manager._cache[(TEST_PATH, image)].priority
+
+ def mocked_resize_image(self, *args):
+ """
+ This is a mocked method, so that we can control the work flow of the image manager.
+ """
+ self.lock.acquire()
+ self.lock.release()
+ # The sleep time is adjusted in the test case.
+ time.sleep(self.sleep_time)
+ return QtGui.QImage()
+
+ def mocked_image_to_byte(self, *args):
+ """
+ This is a mocked method, so that we can control the work flow of the image manager.
+ """
+ self.lock.acquire()
+ self.lock.release()
+ # The sleep time is adjusted in the test case.
+ time.sleep(self.sleep_time)
+ return ''
\ No newline at end of file
=== added file 'tests/resources/church2.jpg'
Binary files tests/resources/church2.jpg 1970-01-01 00:00:00 +0000 and tests/resources/church2.jpg 2014-04-15 20:38:31 +0000 differ
=== added file 'tests/resources/church3.jpg'
Binary files tests/resources/church3.jpg 1970-01-01 00:00:00 +0000 and tests/resources/church3.jpg 2014-04-15 20:38:31 +0000 differ
=== added file 'tests/resources/church4.jpg'
Binary files tests/resources/church4.jpg 1970-01-01 00:00:00 +0000 and tests/resources/church4.jpg 2014-04-15 20:38:31 +0000 differ
Follow ups