def render_ticket_status_svg(ticket): """ Return the svg status image for the given ticket. """ try: if 'fast' in request.args: info = tickets.find_one({'id': ticket}) else: info = scrape(ticket, db=db) except: info = tickets.find_one({'id': ticket}) if 'base' in request.args: base = request.args.get('base') else: base = latest_version(info.get('reports', [])) status = get_ticket_status(info, base=base)[1] # single status path = status_image_path(status, image_type='svg') # with no base response = make_response(open(path).read()) response.headers['Content-type'] = 'image/svg+xml' response.headers['Cache-Control'] = 'no-cache' return response
def render_ticket_status(ticket): """ Return the status image for the given ticket. This now only renders a png image with the base. """ try: if 'fast' in request.args: info = tickets.find_one({'id': ticket}) else: info = scrape(ticket, db=db) except: info = tickets.find_one({'id': ticket}) if 'base' in request.args: base = request.args.get('base') else: base = latest_version(info.get('reports', [])) # status = get_ticket_status(info, base=base)[2] # composite status if 'fast' in request.args: display_base = None else: display_base = base response = make_response(create_base_image(base=display_base)) response.headers['Content-type'] = 'image/png' response.headers['Cache-Control'] = 'no-cache' return response
def post_report(ticket_id): """ Posting a report to the database of reports. """ try: ticket = tickets.find_one({'id': ticket_id}) if ticket is None: ticket = scrape(ticket_id) if 'reports' not in ticket: ticket['reports'] = [] report = json.loads(request.form.get('report')) assert (isinstance(report, dict)), "report is not a dict" for fld in ['status', 'spkgs', 'base', 'machine', 'time']: assert (fld in report), "{} missing in report".format(fld) machine_name = report['machine'][-1] if machine_name in BLACKLIST: msg = 'machine {} is blacklisted'.format(machine_name) raise RuntimeError(msg) prune_pending(ticket, report['machine']) ticket['reports'].append(report) db.logs.put(request.files.get('log'), _id=log_name(ticket_id, report)) if 'retry' in ticket: ticket['retry'] = False ticket['last_activity'] = now_str() db.save_ticket(ticket) return "ok (report successfully posted)" except: traceback.print_exc() return "error in posting the report"
def render_ticket_status(ticket): try: if 'fast' in request.args: info = tickets.find_one({'id': ticket}) else: info = trac.scrape(ticket, db=db) except: info = tickets.find_one({'id': ticket}) if 'base' in request.args: base = request.args.get('base') else: base = latest_version(info['reports'] or []) status = get_ticket_status(info, base=base)[2] if 'fast' in request.args: display_base = None else: display_base = base response = make_response(create_status_image(status, base=display_base)) response.headers['Content-type'] = 'image/png' response.headers['Cache-Control'] = 'no-cache' return response
def get_plugin_data(id, plugin_name, timestamp): ticket = tickets.find_one({'id': int(id)}) if ticket is None: return "Unknown ticket: " + id for report in ticket['reports']: if report['time'] == timestamp: for plugin in report['plugins']: if plugin[0] == plugin_name: response = make_response(json.dumps(plugin[2], default=lambda x: None, indent=4)) response.headers['Content-type'] = 'text/plain' return response return "Unknown plugin: " + plugin_name return "Unknown report: " + timestamp
def render_ticket_status(ticket): try: info = trac.scrape(ticket, db=db) except: info = tickets.find_one({'id': ticket}) if 'reports' in info: base = latest_version(current_reports(info)) else: base = None status = get_ticket_status(info, base=base)[2] response = make_response(create_status_image(status, base=base)) response.headers['Content-type'] = 'image/png' response.headers['Cache-Control'] = 'no-cache' return response
def render_ticket(ticket): try: info = trac.scrape(ticket, db=db, force='force' in request.args) except: info = tickets.find_one({'id': ticket}) if info is None: return "No such ticket." if 'kick' in request.args: info['retry'] = True db.save_ticket(info) if 'reports' in info: info['reports'].sort(lambda a, b: -cmp(a['time'], b['time'])) else: info['reports'] = [] old_reports = list(info['reports']) patchbot.prune_pending(info) if old_reports != info['reports']: db.save_ticket(info) def format_info(info): new_info = {} for key, value in info.items(): if key == 'patches': new_info['patches'] = format_patches(ticket, value) elif key == 'reports' or key == 'pending': pass elif key == 'depends_on': new_info[key] = ', '.join("<a href='/ticket/%s'>%s</a>" % (a, a) for a in value) elif key == 'authors': new_info[key] = ', '.join("<a href='/ticket/?author=%s'>%s</a>" % (a,a) for a in value) elif key == 'participants': new_info[key] = ', '.join("<a href='/ticket/?participant=%s'>%s</a>" % (a,a) for a in value) elif isinstance(value, list): new_info[key] = ', '.join(value) elif key not in ('id', '_id'): new_info[key] = value return new_info def preprocess_reports(all): for item in all: if 'patches' in item: required = info['depends_on'] + info['patches'] item['patch_list'] = format_patches(ticket, item['patches'], item.get('deps'), required) if item['base'] != base: item['base'] = "<span style='color: red'>%s</span>" % item['base'] if 'time' in item: item['log'] = log_name(info['id'], item) yield item return render_template("ticket.html", reports=preprocess_reports(info['reports']), ticket=ticket, info=format_info(info), status=get_ticket_status(info, base=base)[2])
def base_reports_by_machine_and_base(): return reports_by_machine_and_base(tickets.find_one({'id': 0}))
def render_ticket(ticket): try: info = trac.scrape(ticket, db=db, force='force' in request.args) except: info = tickets.find_one({'id': ticket}) if info is None: return "No such ticket." if 'kick' in request.args: info['retry'] = True db.save_ticket(info) if 'reports' in info: info['reports'].sort(lambda a, b: -cmp(a['time'], b['time'])) else: info['reports'] = [] base_reports = base_reports_by_machine_and_base() old_reports = list(info['reports']) patchbot.prune_pending(info) if old_reports != info['reports']: db.save_ticket(info) def format_info(info): new_info = {} for key, value in info.items(): if key == 'patches': new_info['patches'] = format_patches(ticket, value) elif key == 'reports' or key == 'pending': pass elif key == 'depends_on': deps_status = {} for dep in tickets.find({'id': {'$in': [int(a) for a in value]}}, ['status', 'id']): if 'closed' in dep['status']: dep['style'] = 'text-decoration: line-through' else: dep['style'] = '' deps_status[dep['id']] = dep new_info[key] = ', '.join("<img src='/ticket/%s/status.png?fast' height=16><a href='/ticket/%s' style='%s'>%s</a>" % (a, a, deps_status[a]['style'], a) for a in value) elif key == 'authors': new_info[key] = ', '.join("<a href='/ticket/?author=%s'>%s</a>" % (a,a) for a in value) elif key == 'participants': new_info[key] = ', '.join("<a href='/ticket/?participant=%s'>%s</a>" % (a,a) for a in value) elif isinstance(value, list): new_info[key] = ', '.join(value) elif key not in ('id', '_id'): new_info[key] = value return new_info def preprocess_reports(all): for item in all: base_report = base_reports.get(item['base'] + "/" + "/".join(item['machine']), base_reports.get(item['base'])) if base_report: item['base_log'] = urllib.quote(log_name(0, base_report)) if 'patches' in item: required = info['depends_on'] + info['patches'] item['patch_list'] = format_patches(ticket, item['patches'], item.get('deps'), required) item['raw_base'] = item['base'] if item['base'] != base: item['base'] = "<span style='color: red'>%s</span>" % item['base'] if 'time' in item: item['log'] = log_name(info['id'], item) yield item def normalize_plugin(plugin): while len(plugin) < 3: plugin.append(None) return plugin return render_template("ticket.html", reports=preprocess_reports(info['reports']), ticket=ticket, info=format_info(info), status=get_ticket_status(info, base=base)[2], normalize_plugin=normalize_plugin)
def render_ticket(ticket): try: info = trac.scrape(ticket, db=db, force='force' in request.args) except: info = tickets.find_one({'id': ticket}) if info is None: return "No such ticket." if 'kick' in request.args: info['retry'] = True db.save_ticket(info) if 'reports' in info: info['reports'].sort(lambda a, b: -cmp(a['time'], b['time'])) else: info['reports'] = [] base_reports = base_reports_by_machine_and_base() old_reports = list(info['reports']) patchbot.prune_pending(info) if old_reports != info['reports']: db.save_ticket(info) def format_info(info): new_info = {} for key, value in info.items(): if key == 'patches': new_info['patches'] = format_patches(ticket, value) elif key == 'reports' or key == 'pending': pass elif key == 'depends_on': deps_status = {} def is_int(a): try: int(a) return True except ValueError: return False for dep in tickets.find({'id': {'$in': [int(a) for a in value if is_int(a)]}}, ['status', 'id']): if 'closed' in dep['status']: dep['style'] = 'text-decoration: line-through' else: dep['style'] = '' deps_status[dep['id']] = dep new_info[key] = ', '.join("<img src='/ticket/%s/status.png?fast' height=16><a href='/ticket/%s' style='%s'>%s</a>" % (a, a, deps_status[a]['style'], a) for a in value) elif key == 'authors': new_info[key] = ', '.join("<a href='/ticket/?author=%s'>%s</a>" % (a,a) for a in value) elif key == 'participants': new_info[key] = ', '.join("<a href='/ticket/?participant=%s'>%s</a>" % (a,a) for a in value) elif isinstance(value, list): new_info[key] = ', '.join(value) elif key not in ('id', '_id'): new_info[key] = value return new_info base = latest_base() def format_git_describe(res): if res: if '-' in res: tag, commits = res.split('-')[:2] return "%s + %s commits" % (tag, commits) elif 'commits' in res: # old style return res else: return res + " + 0 commits" else: return '?' def preprocess_reports(all): for item in all: base_report = base_reports.get(item['base'] + "/" + "/".join(item['machine']), base_reports.get(item['base'])) if base_report: item['base_log'] = urllib.quote(log_name(0, base_report)) if 'patches' in item: required = info['depends_on'] + info['patches'] item['patch_list'] = format_patches(ticket, item['patches'], item.get('deps'), required) if 'git_base' in item: git_log = item.get('git_log') item['git_log_len'] = '?' if git_log is None else len(git_log) item['raw_base'] = item['base'] if compare_version(item['base'], base) < 0: item['base'] = "<span style='color: red'>%s</span>" % item['base'] if 'time' in item: item['log'] = log_name(info['id'], item) if 'git_commit_human' not in item: item['git_commit_human'] = "%s new commits" % len(item['log']) for x in ('commit', 'base', 'merge'): field = 'git_%s_human' % x item[field] = format_git_describe(item.get(field, None)) yield item def normalize_plugin(plugin): while len(plugin) < 3: plugin.append(None) return plugin def sort_fields(items): return sorted(items, key=(lambda x: (x[0] != 'title', x))) return render_template("ticket.html", reports=preprocess_reports(info['reports']), ticket=ticket, info=format_info(info), status=get_ticket_status(info, base=base)[2], normalize_plugin=normalize_plugin, sort_fields=sort_fields)
def base_reports_by_machine_and_base(): """ reports on the base branch (pseudo-ticket 0) """ return reports_by_machine_and_base(tickets.find_one({'id': 0}))
def render_ticket(ticket): """ reports on a given ticket possible options: ?force and ?kick ?force will refresh the info in the patchbot-server database ?kick will tell the patchbot-clients to retry the ticket ?base to select reports according to their base """ latest = latest_base() if 'base' in request.args: chosen_base = request.args.get('base') else: chosen_base = 'all' if ticket != 0 else 'develop' if chosen_base == 'latest' or chosen_base == 'develop': chosen_base = latest try: info = scrape(ticket, db=db, force='force' in request.args) except: info = tickets.find_one({'id': ticket}) if info is None: return "No such ticket." if 'kick' in request.args: info['retry'] = True db.save_ticket(info) if 'reports' in info: info['reports'].sort(lambda a, b: -cmp(a['time'], b['time'])) else: info['reports'] = [] base_reports = base_reports_by_machine_and_base() old_reports = list(info['reports']) prune_pending(info) if old_reports != info['reports']: db.save_ticket(info) def format_info(info): new_info = {} for key, value in info.items(): if key in ['patches', 'reports', 'pending']: pass elif key == 'depends_on': deps_status = {} def is_int(a): try: int(a) return True except ValueError: return False for dep in tickets.find({'id': {'$in': [int(a) for a in value if is_int(a)]}}, ['status', 'id']): if 'closed' in dep['status']: dep['style'] = 'text-decoration: line-through' else: dep['style'] = '' deps_status[dep['id']] = dep new_info[key] = ', '.join("<img src='/ticket/%s/status.svg?fast' height=16><a href='/ticket/%s' style='%s'>%s</a>" % (a, a, deps_status[a]['style'], a) for a in value) elif key == 'authors': new_info[key] = ', '.join("<a href='/ticket/?author=%s'>%s</a>" % (a, a) for a in value) elif key == 'authors_fullnames': link = u"<a href='http://git.sagemath.org/sage.git/log/?qt=author&q={}'>{}</a>" auths = u", ".join(link.format(a.replace(u" ", u"%20"), a) for a in value) trust_check = u"(<a href='/trust_check?who=" trust_check += u",".join(u"{}".format(a) for a in value) trust_check += u"'>Check trust</a>) " new_info[key] = trust_check + auths elif key == 'participants': parts = ', '.join("<a href='/ticket/?participant=%s'>%s</a>" % (a, a) for a in value) new_info[key] = parts elif key == 'git_branch': new_info[key] = '<a href="http://git.sagemath.org/sage.git/log/?h=%s">%s</a>' % (value, value) elif key == 'spkgs': new_info[key] = ', '.join("<a href='%s'>%s</a>" % (a, a) for a in value) elif isinstance(value, list): new_info[key] = ', '.join(value) elif key not in ('id', '_id'): new_info[key] = value return new_info def format_git_describe(res): if res: if '-' in res: tag, commits = res.split('-')[:2] return "%s + %s commits" % (tag, commits) elif 'commits' in res: # old style return res else: return res + " + 0 commits" else: return '?' def preprocess_reports(all): for item in all: base_of_this_report = item['base'] base_report = base_reports.get(item['base'] + "/" + "/".join(item['machine']), base_reports.get(item['base'])) if base_report: item['base_log'] = quote(log_name(0, base_report)) if 'git_base' in item: git_log = item.get('git_log') item['git_log_len'] = '?' if git_log is None else len(git_log) item['raw_base'] = item['base'] if compare_version(item['base'], latest) < 0: item['base'] = "<span style='color: red'>%s</span>" % item['base'] if 'time' in item: item['log'] = log_name(info['id'], item) if 'git_commit_human' not in item: item['git_commit_human'] = "%s new commits" % len(item['log']) for x in ('commit', 'base', 'merge'): field = 'git_%s_human' % x item[field] = format_git_describe(item.get(field, None)) if chosen_base == 'all' or chosen_base == base_of_this_report: yield item def normalize_plugin(plugin): while len(plugin) < 3: plugin.append(None) return plugin def sort_fields(items): return sorted(items, key=(lambda x: (x[0] != 'title', x))) status_data = get_ticket_status(info, base=latest)[1] # single status return render_template("ticket.html", reports=preprocess_reports(info['reports']), ticket=ticket, info=format_info(info), status=status_data, normalize_plugin=normalize_plugin, sort_fields=sort_fields)
def ticket_list(): authors = None machine = None if 'base' in request.args: base = request.args.get('base') if base == 'all': base = None elif base == 'develop': base = 'latest' else: base = 'latest' query = get_query(request.args) if 'machine' in request.args: machine = request.args.get('machine').split(':') if 'authors' in request.args: authors = request.args.get('authors').split(':') if 'order' in request.args: order = request.args.get('order') else: order = 'last_activity' limit = int(request.args.get('limit', 1000)) print(query) all = filter_on_authors(tickets.find(query).sort(order).limit(limit), authors) if 'raw' in request.args: # raw json file for communication with patchbot clients def filter_reports(all): for ticket in all: current = sorted(current_reports(ticket), key=lambda report: report['time']) ticket['reports'] = list(reversed(current))[:10] for report in ticket['reports']: report['plugins'] = '...' yield ticket all = filter_reports(all) if 'pretty' in request.args: indent = 4 else: indent = None response = make_response(json.dumps(list(all), default=lambda x: None, indent=indent)) response.headers['Content-type'] = 'text/plain; charset=utf-8' return response summary = {key: 0 for key in status_order} def preprocess(all): for ticket in all: ticket['report_count'], ticket['report_status'], ticket['report_status_composite'] = get_ticket_status(ticket, machine=machine, base=base or 'latest') if 'reports' in ticket: ticket['pending'] = len([r for r in ticket['reports'] if r['status'] == 'Pending']) summary[ticket['report_status']] += 1 yield ticket ticket0 = tickets.find_one({'id': 0}) base_status = get_ticket_status(ticket0, base) versions = list(set(report['base'] for report in ticket0['reports'])) versions.sort(compare_version) versions = [v for v in versions if compare_version(v, OLDEST) == 1] versions = [(v, get_ticket_status(ticket0, v)) for v in versions] return render_template("ticket_list.html", tickets=preprocess(all), summary=summary, base=base, base_status=base_status, versions=versions, status_order=status_order, compare_version=compare_version)