mirror of
https://github.com/odoo/runbot.git
synced 2025-03-15 23:45:44 +07:00
[IMP] forwardport: hall of fame layout and informations
The list of outstanding forwardports was pretty messy as the ordering was unclear and there was little way to really drill into the thing. * Shows outstanding forward ports sorted by merged date ascending, the oldest-merged PRs are the ones most in need of fixing while PRs which were only just merged can safely be ignored. * List reviewers with outstanding forward-ports, allow filtering by clicking on their name, allow deseleting through the subtitle of the page. * Don't display reviewer in list when page is already filtered by reviewer. Also improve PR page a bit: * Add reviewer. * Add direct link to backend (closes #524). Closes #529
This commit is contained in:
parent
c6755a045a
commit
6c60d59b11
@ -39,31 +39,51 @@
|
||||
<field name="arch" type="xml">
|
||||
<t name="Outstanding forward ports" t-name="forwardport.outstanding_fp">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="hof" t-value="env['runbot_merge.pull_requests']._hall_of_shame()"/>
|
||||
<div id="wrap" class="oe_structure oe_empty"><div class="container-fluid">
|
||||
<ul class="alert bg-light list-inline">
|
||||
<span t-foreach="hof.reviewers" t-as="count" class="list-inline-item">
|
||||
<a t-attf-href="?reviewer={{count[0].id}}"
|
||||
t-field="count[0].display_name"
|
||||
t-att-title="count[1]"
|
||||
/>
|
||||
</span>
|
||||
</ul>
|
||||
<h1>List of pull requests with outstanding forward ports</h1>
|
||||
<dl><t t-foreach="env['runbot_merge.pull_requests']._outstanding()" t-as="x">
|
||||
<t t-set="reviewer" t-value="env['res.partner'].browse(int(request.params.get('reviewer') or 0))"/>
|
||||
<form method="get" action="" id="reset-filter"/>
|
||||
<h2 t-if="reviewer" class="text-muted">
|
||||
merged by <span t-field="reviewer.display_name" t-attf-title="@{{reviewer.github_login}}"/>
|
||||
<button form="reset-filter" type="submit"
|
||||
name="reviewer" value=""
|
||||
title="See All" class="btn fa fa-times"/>
|
||||
</h2>
|
||||
<dl><t t-foreach="hof.outstanding" t-as="x">
|
||||
<t t-set="source" t-value="x[0]"/>
|
||||
<t t-set="prs" t-value="x[1]"/>
|
||||
<dt>
|
||||
<a t-att-href="source.url"><span t-field="source.display_name"/></a>
|
||||
by <span t-field="source.author.display_name"
|
||||
t-attf-title="@{{source.author.github_login}}"/>
|
||||
merged <span t-field="source.merge_date"
|
||||
t-options="{'widget': 'relative'}"
|
||||
t-att-title="source.merge_date"/>
|
||||
by <span t-field="source.reviewed_by.display_name"
|
||||
t-attf-title="@{{source.reviewed_by.github_login}}"/>
|
||||
</dt>
|
||||
<dd>
|
||||
Outstanding forward-ports:
|
||||
<ul>
|
||||
<li t-foreach="prs" t-as="p">
|
||||
<a t-att-href="p.url"><span t-field="p.display_name"/></a>
|
||||
(<span t-field="p.state"/>)
|
||||
targeting <span t-field="p.target.name"/>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
<t t-if="not reviewer or source.reviewed_by == reviewer">
|
||||
<dt>
|
||||
<a t-att-href="source.url"><span t-field="source.display_name"/></a>
|
||||
by <span t-field="source.author.display_name"
|
||||
t-attf-title="@{{source.author.github_login}}"/>
|
||||
merged <span t-field="source.merge_date"
|
||||
t-options="{'widget': 'relative'}"
|
||||
t-att-title="source.merge_date"/>
|
||||
<t t-if="not reviewer">
|
||||
by <span t-field="source.reviewed_by.display_name"
|
||||
t-attf-title="@{{source.reviewed_by.github_login}}"/>
|
||||
</t>
|
||||
</dt>
|
||||
<dd>
|
||||
Outstanding forward-ports:
|
||||
<ul>
|
||||
<li t-foreach="x.prs" t-as="p">
|
||||
<a t-att-href="p.url"><span t-field="p.display_name"/></a>
|
||||
(<span t-field="p.state"/>)
|
||||
targeting <span t-field="p.target.name"/>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</t>
|
||||
</t></dl>
|
||||
</div></div>
|
||||
</t>
|
||||
@ -78,6 +98,8 @@
|
||||
<dd>
|
||||
<span t-field="pr.merge_date" t-options="{'widget': 'relative'}"
|
||||
t-att-title="pr.merge_date"/>
|
||||
by <span t-field="pr.reviewed_by.display_name"
|
||||
t-attf-title="@{{pr.reviewed_by.github_login}}"/>
|
||||
</dd>
|
||||
</t>
|
||||
<t t-if="pr.source_id">
|
||||
|
@ -13,6 +13,7 @@ it up), ...
|
||||
"""
|
||||
import ast
|
||||
import base64
|
||||
import collections
|
||||
import contextlib
|
||||
import datetime
|
||||
import itertools
|
||||
@ -24,6 +25,7 @@ import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import typing
|
||||
|
||||
import dateutil.relativedelta
|
||||
import requests
|
||||
@ -1027,25 +1029,46 @@ stderr:
|
||||
repo.config('--add', 'remote.origin.fetch', '+refs/pull/*/head:refs/heads/pull/*')
|
||||
return repo
|
||||
|
||||
def _outstanding(self, cutoff=None):
|
||||
def _outstanding(self, cutoff):
|
||||
""" Returns "outstanding" (unmerged and unclosed) forward-ports whose
|
||||
source was merged before ``cutoff`` (all of them if not provided).
|
||||
|
||||
:param str cutoff: a datetime (ISO-8601 formatted)
|
||||
:returns: an iterator of (source, forward_ports)
|
||||
"""
|
||||
cutoff_terms = []
|
||||
if cutoff:
|
||||
# original merged more than <cutoff> ago
|
||||
cutoff_terms = [('source_id.merge_date', '<', cutoff)]
|
||||
return groupby(self.env['runbot_merge.pull_requests'].search([
|
||||
# only FP PRs
|
||||
('source_id', '!=', False),
|
||||
# active
|
||||
('state', 'not in', ['merged', 'closed']),
|
||||
*cutoff_terms,
|
||||
('source_id.merge_date', '<', cutoff),
|
||||
], order='source_id, id'), lambda p: p.source_id)
|
||||
|
||||
def _hall_of_shame(self):
|
||||
"""Provides data for the HOS view
|
||||
|
||||
* outstanding forward ports per reviewer
|
||||
* pull requests with outstanding forward ports, oldest-merged first
|
||||
"""
|
||||
cutoff_dt = datetime.datetime.now() - DEFAULT_DELTA
|
||||
outstanding = self.env['runbot_merge.pull_requests'].search([
|
||||
('source_id', '!=', False),
|
||||
('state', 'not in', ['merged', 'closed']),
|
||||
('source_id.merge_date', '<', cutoff_dt),
|
||||
], order=None)
|
||||
# only keep merged because apparently some PRs are in a weird spot
|
||||
# where they're sources but closed?
|
||||
sources = outstanding.mapped('source_id').filtered('merge_date').sorted('merge_date')
|
||||
outstandings = []
|
||||
reviewers = collections.Counter()
|
||||
for source in sources:
|
||||
outstandings.append(Outstanding(source=source, prs=source.forwardport_ids & outstanding))
|
||||
reviewers[source.reviewed_by] += 1
|
||||
return HallOfShame(
|
||||
reviewers=reviewers.most_common(),
|
||||
outstanding=outstandings,
|
||||
)
|
||||
|
||||
def _reminder(self):
|
||||
cutoff = self.env.context.get('forwardport_updated_before') \
|
||||
or fields.Datetime.to_string(datetime.datetime.now() - DEFAULT_DELTA)
|
||||
@ -1178,3 +1201,11 @@ def _clean_rename(s):
|
||||
l for l in s.splitlines()
|
||||
if not l.startswith('Performing inexact rename detection')
|
||||
)
|
||||
|
||||
class HallOfShame(typing.NamedTuple):
|
||||
reviewers: list
|
||||
outstanding: list
|
||||
|
||||
class Outstanding(typing.NamedTuple):
|
||||
source: object
|
||||
prs: object
|
||||
|
@ -393,9 +393,13 @@
|
||||
<template id="view_pull_request">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap"><div class="container-fluid">
|
||||
<a t-att-href="pr.github_url">
|
||||
<h1 t-field="pr.display_name"/>
|
||||
<h1>
|
||||
<a t-att-href="pr.github_url" t-field="pr.display_name">
|
||||
</a>
|
||||
<a t-attf-href="/web#view_type=form&model=runbot_merge.pull_requests&id={{pr.id}}"
|
||||
class="btn btn-sm btn-secondary align-top float-right"
|
||||
groups="base.group_user">View in backend</a>
|
||||
</h1>
|
||||
<h6>Created by <span t-field="pr.author.display_name"/></h6>
|
||||
<t t-set="tmpl">
|
||||
<t t-if="pr.state in ('merged', 'closed', 'error')"><t t-esc="pr.state"/></t>
|
||||
|
Loading…
Reference in New Issue
Block a user