--- a/candolint/handlers.py Sat Sep 16 17:37:38 2017 +0800
+++ b/candolint/handlers.py Sat Sep 16 17:41:43 2017 +0800
from __future__ import absolute_import, division
+from difflib import unified_diff
from peewee import DoesNotExist
self.render('check.html', project=project, check=check, lines=lines, adapter=adapter)
+class CompareHandler(BaseHandler):
+ def get(self, domain, user, name, check_num, reference_num):
+ project = get_project_or_404(domain, user, name)
+ adapter = project.get_adapter()
+ check = get_check_or_404(project, check_num)
+ reference = get_check_or_404(project, reference_num)
+ lines = json_decode(check.lines)
+ reflines = json_decode(reference.lines)
+ rcl = [l['text'] for l in reflines if l.get('task') == 'checks']
+ cl = [l['text'] for l in lines if l.get('task') == 'checks']
+ diff = unified_diff(rcl, cl, n=max(len(rcl), len(cl)))
+ for text in list(diff)[4:]:
+ if text.startswith('+'):
+ elif text.startswith('-'):
+ line['cls'] = 'removed'
+ difflines.append({'text': 'Diff is empty', 'cls': 'meta'})
+ self.render('compare.html', project=project, check=check, reference=reference, lines=difflines, adapter=adapter)
class StatusHandler(BaseHandler):
def get(self, domain, user, name):
project = get_project_or_404(domain, user, name)
--- a/static/candolint.css Sat Sep 16 17:37:38 2017 +0800
+++ b/static/candolint.css Sat Sep 16 17:41:43 2017 +0800
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/compare.html Sat Sep 16 17:41:43 2017 +0800
+{% extends "base.html" %}
+{% block title %}#{{ reference.ordinal }} and #{{ check.ordinal }}{% end %}
+ <div class="uk-container uk-container-center uk-margin-large-top">
+ {% module Template('ui/project-link.html', project=project) %}
+ <span class="uk-text-nowrap">
+ · comparing <a href="{{ project.get_url() }}/{{ reference.ordinal }}">#{{ reference.ordinal }}</a>
+ and <a href="{{ project.get_url() }}/{{ check.ordinal }}">#{{ check.ordinal }}</a>
+ {% if check.change.branch != reference.change.branch %}
+ Checks are for different branches: {{ check.change.branch }} and {{ reference.change.branch }}.
+ {% if check.change_id == reference.change_id %}
+ Both checks are for the same commit:
+ {% set change = check.change %}
+ <a href="{{ adapter.get_commit_url(change) }}">{% if change.rev is not None %}{{ change.rev }}:{% end %}{{ change.node[:12] }}</a>.
+ {% include ui/check-log.html %}
--- a/tests/test_viewer.py Sat Sep 16 17:37:38 2017 +0800
+++ b/tests/test_viewer.py Sat Sep 16 17:41:43 2017 +0800
message='component: do a thing',
+ ordinal=Check.get_next_ordinal(project),
+ started=datetime.fromtimestamp(0),
+ finished=datetime.fromtimestamp(0),
'text': '# C&O job started: 2016-08-20T02:38:06+00:00',
ns = {'atom': 'http://www.w3.org/2005/Atom'}
title = root.find('./atom:entry/atom:title', ns)
- assert title.text == 'Check #1: 1 error, 1 warning'
+ assert title.text.startswith('Check #')
+ assert title.text.endswith(' 1 error, 1 warning')
updates = [el.text for el in root.findall('.//atom:updated', ns)]
- assert len(updates) == 2
+ assert len(updates) == min(Check.select().count(), 20) + 1
assert updates[0] == updates[1] == '2016-08-20T02:38:53Z'
assert response.headers['Content-Type'] == 'text/plain; charset=utf-8'
assert 'test.py' in response.body
+ def test_compare(self):
+ base_url = '/example.com/alice/test-viewer/latest'
+ response = self.fetch(base_url + '/compare/latest')
+ assert response.code == 200
+ assert 'same commit' in response.body
+ assert 'Diff is empty' in response.body
+ response = self.fetch(base_url + '/compare/1')
+ assert response.code == 200
+ assert 'same commit' in response.body
+ assert 'E501' in response.body
response = self.fetch('/butt.cloud/cyber/wizard-attack/status.svg')
assert response.code == 404
--- a/viewer.py Sat Sep 16 17:37:38 2017 +0800
+++ b/viewer.py Sat Sep 16 17:41:43 2017 +0800
(project_re, h.ProjectHandler),
(project_re + r'/atom', h.AtomHandler),
(project_re + r'/(\d+|latest)(?:/(raw))?', h.CheckHandler),
+ (project_re + r'/(\d+|latest)/compare/(\d+|latest)', h.CompareHandler),
(project_re + r'/status\.svg', h.StatusHandler),
(r'.*', h.ErrorHandler, {'status_code': 404})