Hello community,
here is the log from the commit of package python-openqa_review for
openSUSE:Factory checked in at 2017-02-07 12:08:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-openqa_review (Old)
and /work/SRC/openSUSE:Factory/.python-openqa_review.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-openqa_review"
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-openqa_review/python-openqa_review.changes
2017-02-03 18:57:56.900896765 +0100
+++
/work/SRC/openSUSE:Factory/.python-openqa_review.new/python-openqa_review.changes
2017-02-07 12:08:20.668222109 +0100
@@ -1,0 +2,18 @@
+Mon Feb 06 17:09:31 UTC 2017 - [email protected]
+
+- Update to version 1.5.0:
+ * Post issue reminder comments from daily review script
+ * tumblesle_release: Add AMQP notification support for 'suse_msg'
+ * tumblesle_release: Add documentation for AMQP notifications
+ * tumblesle_release: Prevent spammy repetition of AMQP notifications
+ * Get rid of duplicate update_jekyll
+ * More tumblesle notifications
+ * Fix tumblesle script not checking for new builds / updated job results
+ * Make tumblesle_release notification connection more resilient
+ * tumblesle_release: Only store in notify_seen on success
+ * Recommend safer installation proposals
+ * Ensure valid python certificates with certifi
+ * Be more specific about the error when file not found in cache
+ * Ensure all data is cached on save in openqa_review_osd_daily_email
+
+-------------------------------------------------------------------
Old:
----
python-openqa_review-1.4.1.tar.gz
New:
----
python-openqa_review-1.5.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-openqa_review.spec ++++++
--- /var/tmp/diff_new_pack.wSZm0W/_old 2017-02-07 12:08:21.188148544 +0100
+++ /var/tmp/diff_new_pack.wSZm0W/_new 2017-02-07 12:08:21.188148544 +0100
@@ -18,7 +18,7 @@
%define short_name openqa_review
Name: python-%{short_name}
-Version: 1.4.1
+Version: 1.5.0
Release: 0
Summary: A review helper script for openQA
License: MIT
++++++ python-openqa_review-1.4.1.tar.gz -> python-openqa_review-1.5.0.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/README.md
new/openqa_review-1.5.0/README.md
--- old/openqa_review-1.4.1/README.md 2017-01-20 14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/README.md 2017-02-06 18:06:38.000000000 +0100
@@ -6,11 +6,19 @@
## Usage
-* Install requirements and package, e.g.
+* Install requirements and package, using an isolated Python environment
+ such as
[VirtualEnv](http://docs.python-guide.org/en/latest/dev/virtualenvs/).
```
-sudo pip install -r requirements.txt
-sudo pip install .
+pip install -r requirements.txt
+pip install .
+```
+
+or if you are using openSUSE distribution, it is recommended to use `zypper`,
+e.g.:
+
+```
+zypper in python-openqa_review
```
* Call `openqa-review` from PATH, e.g. with `--help`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openqa_review-1.4.1/bin/openqa_review_osd_daily_email
new/openqa_review-1.5.0/bin/openqa_review_osd_daily_email
--- old/openqa_review-1.4.1/bin/openqa_review_osd_daily_email 2017-01-20
14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/bin/openqa_review_osd_daily_email 2017-02-06
18:06:38.000000000 +0100
@@ -9,7 +9,8 @@
load_args="${load_args:-"--load --load-dir=${tmp}"}"
openqa_review_email_args="${openqa_review_email_args:-"${load_args}"}"
openqa_review_html_args="${openqa_review_html_args:-"${load_args}
--report-links"}"
-openqa_review_save_args="${openqa_review_save_args:-"--report-links --save
--save-dir ${tmp}"}"
+openqa_review_save_args="${openqa_review_save_args:-"--report-links
--reminder-comment-on-issues --dry-run --save --save-dir ${tmp}"}"
+openqa_review_reminder_args="${openqa_review_reminder_args:-"${load_args}
--reminder-comment-on-issues"}"
openqa_review="${openqa_review:-"$(which openqa-review)"}"
TPL="${TPL:-"dashboard_files/dashboard.html.in"}"
# the awk call is to ignore the "InsecureWarning" and the following blank line
@@ -48,3 +49,5 @@
$(<$TPL)
EOF
" > ${html_target}
+
+${openqa_review} $openqa_review_args $openqa_review_reminder_args > /dev/null
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openqa_review-1.4.1/bin/tumblesle-release-server-12sp3-x86_64
new/openqa_review-1.5.0/bin/tumblesle-release-server-12sp3-x86_64
--- old/openqa_review-1.4.1/bin/tumblesle-release-server-12sp3-x86_64
2017-01-20 14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/bin/tumblesle-release-server-12sp3-x86_64
2017-02-06 18:06:38.000000000 +0100
@@ -1 +1 @@
-flock -n /tmp/tumblesle_release.lock -c "tumblesle-release --openqa-host
http://openqa.suse.de --group-id 55 --product 'Server' --src
openqa:/var/lib/openqa/factory/ --match '*SP3*Server*x86_64*' --match-hdd
'SLES-12-SP3-x86_64*' -vvvv --post-release-hook
/home/tumblesle/bin/update_jekyll $@" 2>&1 | tee -a
/var/log/tumblesle/tumblesle-release.log
+flock -n /tmp/tumblesle_release.lock -c "tumblesle-release --openqa-host
http://openqa.suse.de --group-id 55 --product 'Server' --src
openqa:/var/lib/openqa/factory/ --match '*SP3*Server*x86_64*' --match-hdd
'SLES-12-SP3-x86_64*' -vvvv --post-release-hook
/home/tumblesle/bin/update_jekyll --seen-maxlen=24 $@" 2>&1 | tee -a
/var/log/tumblesle/tumblesle-release.log
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/bin/update_jekyll
new/openqa_review-1.5.0/bin/update_jekyll
--- old/openqa_review-1.4.1/bin/update_jekyll 2017-01-20 14:23:49.000000000
+0100
+++ new/openqa_review-1.5.0/bin/update_jekyll 2017-02-06 18:06:38.000000000
+0100
@@ -1,5 +1,7 @@
#!/bin/sh -e
-old=$(find /srv/www/tumblesle -maxdepth 1 | head -n -3 | grep '[0-9]\+$')
-chmod -R +w ${old}
-rm -rf ${old}
+old=$(find /srv/www/tumblesle -maxdepth 1 | head -n -3 | grep '[0-9]\+$') ||
true
+if [ "$old" != "" ]; then
+ chmod -R +w ${old}
+ rm -rf ${old}
+fi
sudo -u wwwrun /srv/jekyll-source/.git/hooks/post-merge
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/openqa_review/browser.py
new/openqa_review-1.5.0/openqa_review/browser.py
--- old/openqa_review-1.4.1/openqa_review/browser.py 2017-01-20
14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/openqa_review/browser.py 2017-02-06
18:06:38.000000000 +0100
@@ -25,6 +25,11 @@
pass
+class CacheNotFoundError(DownloadError):
+ """content could not retrieved from cache."""
+ pass
+
+
def url_to_filename(url):
"""
Convert URL to a valid, unambigous filename.
@@ -88,7 +93,7 @@
msg = "Request to %s was not successful, file %s not
found" % (url, filename)
log.info(msg)
# as 'load' simulates downloading we also have to simulate
an appropriate error
- raise DownloadError(msg)
+ raise CacheNotFoundError(msg)
else: # pragma: no cover
raise
content = json.loads(raw) if as_json else raw
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/openqa_review/openqa_review.py
new/openqa_review-1.5.0/openqa_review/openqa_review.py
--- old/openqa_review-1.4.1/openqa_review/openqa_review.py 2017-01-20
14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/openqa_review/openqa_review.py 2017-02-06
18:06:38.000000000 +0100
@@ -614,6 +614,7 @@
def add_comment(self, comment):
"""Add a comment to an issue with RPC/REST operations."""
+ log.info("Posting a comment on %s ticket [%s](%s)" % (self.issue_type,
self.bugref, self.bugref_href))
if self.issue_type == 'bugzilla':
self.bugzilla_browser.json_rpc_post('/jsonrpc.cgi',
'Bug.add_comment', {
"id": self.bugid,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openqa_review-1.4.1/openqa_review/tumblesle_release.py
new/openqa_review-1.5.0/openqa_review/tumblesle_release.py
--- old/openqa_review-1.4.1/openqa_review/tumblesle_release.py 2017-01-20
14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/openqa_review/tumblesle_release.py 2017-02-06
18:06:38.000000000 +0100
@@ -16,6 +16,10 @@
directory structure is available on. The source, i.e. where to copy assets
from,
can be remote and the path can be specified in an rsync-compatible way, e.g.
"openqa:/var/lib/openqa/factory/"
+
+Notifications over AMQP are sent out if a host has been configured
+appropriately in the configuration file (see config file example). The
+notifications are serialized in JSON strings.
"""
# Python 2 and 3: easiest option
@@ -29,11 +33,13 @@
import fnmatch
import glob
import logging
+import json
import os.path
+import pika
import re
import sys
import time
-from collections import defaultdict
+from collections import defaultdict, deque
from configparser import ConfigParser
from subprocess import check_call
@@ -56,6 +62,8 @@
# example scenario: openSUSE-Tumbleweed-DVD-x86_64-gnome@64bit
whitelist = arm7l-foo,bar@uefi
+#[notification]
+#host = localhost
"""
@@ -101,6 +109,32 @@
log.info("Whitelist content for %s: %s" % (self.args.product,
self.whitelist))
self.release_info_path = os.path.join(self.args.dest,
self.args.release_file)
self.browser = Browser(args, args.openqa_host)
+ if not config.has_section('notification'):
+ return
+ notify_host = config.get('notification', 'host',
fallback='kazhua.suse.de')
+ self.notify_connection =
pika.BlockingConnection(pika.ConnectionParameters(host=notify_host))
+ self.notify_channel = self.notify_connection.channel()
+ self.notify_channel.exchange_declare(exchange='pubsub', type='topic',
passive=True, durable=True)
+ self.notify_topic = 'suse.tumblesle'
+ self.notify_seen = deque(maxlen=args.seen_maxlen)
+
+ def __del__(self):
+ """Cleanup notification objects."""
+ if not hasattr(self, 'notify_connection'):
+ return
+ self.notify_connection.close()
+
+ def notify(self, message, topic='info'):
+ """Send notification over messaging bus."""
+ if not hasattr(self, 'notify_channel'):
+ log.debug("No notification channel enabled, discarding notify.")
+ return
+ body = json.dumps(message)
+ if body in self.notify_seen:
+ log.debug("notification message already sent out recently, not
resending: %s" % body)
+ return
+ self.notify_channel.basic_publish(exchange='pubsub',
routing_key='.'.join([self.notify_topic, topic]), body=body)
+ self.notify_seen.append(body)
def run(self, do_run=True):
"""Continously run while 'do_run' is True, check for last build and
release if satisfying."""
@@ -128,7 +162,7 @@
def is_matching_iso(i):
return 'iso' in i['type'] and 'Staging' not in i['name'] and
re.match(match_re, i['name'])
log.debug("Finding most recent ISO matching regex '%s'" % match_re)
- assets = self.browser.get_json('/api/v1/assets')['assets']
+ assets = self.browser.get_json('/api/v1/assets',
cache=self.args.load)['assets']
isos = [i['name'] for i in assets if is_matching_iso(i)]
return isos
@@ -136,7 +170,7 @@
"""Retrieve jobs for current group by build id, returns dict with
result as keys."""
group_id = int(self.args.group_id)
log.debug("Getting jobs in build %s ..." % build)
- jobs_build =
self.browser.get_json('/api/v1/jobs?state=done&latest=1&build=%s&group_id=%s' %
(build, group_id))['jobs']
+ jobs_build =
self.browser.get_json('/api/v1/jobs?state=done&latest=1&build=%s&group_id=%s' %
(build, group_id), cache=self.args.load)['jobs']
jobs_in_build_product = [i for i in jobs_build if i['group_id'] ==
group_id]
jobs_by_result = defaultdict(list)
for job in jobs_in_build_product:
@@ -215,6 +249,7 @@
new_fixed = sets['released'].difference(sets['last'])
log.info("Regression in new build %s, new failures: %s" %
(build['last'], ', '.join(new_failures)))
log.debug("new fixed: %s" % ', '.join(new_fixed))
+ self.notify({'build': build['last'], 'new_failures':
list(new_failures)}, topic='regression')
# # assuming every job in released_failed is in whitelist
# if len(hard_failed) > previous_hard_failed:
@@ -280,6 +315,7 @@
self.update_symlinks(build_dest)
self.update_release_info()
log.debug("Release DONE")
+ self.notify({'build': self.release_build}, topic='release')
if self.args.post_release_hook:
log.debug("Calling post_release_hook '%s'" %
self.args.post_release_hook)
check_call(self.args.post_release_hook)
@@ -343,6 +379,12 @@
parser.add_argument('--post-release-hook',
help="Specify application path for a post-release hook
which is called after every successful release",
default=None)
+ parser.add_argument('--seen-maxlen', type=int,
+ help="""The length of the 'seen' buffer for
notifications. Any AMQP notification is stored in a FIFO and
+ before sending it is checked if the notification was
already sent out recently with same content.
+ Together with '--sleeptime' the interval under which
the same message would be resent can be configured,
+ e.g. maxlen*sleeptime = minimum time of reappearence
(s)""",
+ default=500)
add_load_save_args(parser)
return parser.parse_args()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/setup.py
new/openqa_review-1.5.0/setup.py
--- old/openqa_review-1.4.1/setup.py 2017-01-20 14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/setup.py 2017-02-06 18:06:38.000000000 +0100
@@ -34,6 +34,11 @@
"humanfriendly",
"requests",
"PyYAML",
+ "pika",
+ "certifi",
+ ],
+ test_require=[
+ "pytest-mock",
],
author="Oliver kurz",
author_email="[email protected]",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/tests/test_tumblesle_release.py
new/openqa_review-1.5.0/tests/test_tumblesle_release.py
--- old/openqa_review-1.4.1/tests/test_tumblesle_release.py 2017-01-20
14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/tests/test_tumblesle_release.py 2017-02-06
18:06:38.000000000 +0100
@@ -73,6 +73,7 @@
args.load_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'tumblesle/0046_0056_new_release')
args.dest = '/tmp/'
args.post_release_hook = None
+ args.seen_maxlen = 1
# Enable saving and disable loading if you want to add new test data
downloaded from hosts
# args.save = True
# args.save_dir = args.load_dir
@@ -175,3 +176,20 @@
tr = tumblesle_release.TumblesleRelease(args)
tr.check_last_builds()
assert tr.release_build == '0215'
+
+
+def test_notifications_are_sent(args, mocker):
+ with TumblesleDirectory(args) as tmp_dir:
+ config_path = os.path.join(tmp_dir, 'config_file')
+ with open(config_path, 'a') as config:
+ config.write("""
+[notification]
+host = localhost
+""")
+ mocker.patch('pika.BlockingConnection')
+ tr = tumblesle_release.TumblesleRelease(args)
+ tr.one_run()
+ assert '{"build": "0056"}' in tr.notify_seen
+ # this will yield the same message and is therefore not sent out again
+ tr.one_run()
+ assert '{"build": "0056"}' in tr.notify_seen
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/tox.ini
new/openqa_review-1.5.0/tox.ini
--- old/openqa_review-1.4.1/tox.ini 2017-01-20 14:23:49.000000000 +0100
+++ new/openqa_review-1.5.0/tox.ini 2017-02-06 18:06:38.000000000 +0100
@@ -51,12 +51,14 @@
deps = -rrequirements.txt
pytest
pytest-cov
+ pytest-mock
[testenv]
commands =
py.test {posargs:-m 'not webtest'}
deps = -rrequirements.txt
pytest
+ pytest-mock
[testenv:webtests]
# This testenv could be called explicitly, e.g. by 'tox -e webtests'.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/openqa_review-1.4.1/update_jekyll
new/openqa_review-1.5.0/update_jekyll
--- old/openqa_review-1.4.1/update_jekyll 2017-01-20 14:23:49.000000000
+0100
+++ new/openqa_review-1.5.0/update_jekyll 1970-01-01 01:00:00.000000000
+0100
@@ -1,7 +0,0 @@
-#!/bin/sh -e
-old=$(find /srv/www/tumblesle -maxdepth 1 | head -n -3 | grep '[0-9]\+$') ||
true
-if [ "$old" != "" ]; then
- chmod -R +w ${old}
- rm -rf ${old}
-fi
-sudo -u wwwrun /srv/jekyll-source/.git/hooks/post-merge