First working version of the app maintainer dashboard

This commit is contained in:
Alexandre Aubin 2018-11-07 20:12:36 +01:00
parent 5f456bbcd7
commit 905ee51e6d
4 changed files with 222 additions and 7 deletions

View file

@ -1,6 +1,7 @@
from flask import render_template, make_response, Blueprint from flask import render_template, make_response, Blueprint
from .models.pr import PullRequest from .models.pr import PullRequest
from .models.appci import App, AppCI, AppCIBranch from .models.applists import App
from .models.appci import AppCI, AppCIBranch
from .models.unlistedapps import UnlistedApp from .models.unlistedapps import UnlistedApp
from .settings import SITE_ROOT from .settings import SITE_ROOT
import json import json
@ -118,6 +119,9 @@ def badge(app):
badge = "level%s.svg" % level if not level is None else "unknown.svg" badge = "level%s.svg" % level if not level is None else "unknown.svg"
if not app.ci_enabled:
badge = "unknown.svg"
svg = open("./app/static/badges/%s" % badge).read() svg = open("./app/static/badges/%s" % badge).read()
response = make_response(svg) response = make_response(svg)
response.content_type = 'image/svg+xml' response.content_type = 'image/svg+xml'
@ -151,3 +155,19 @@ def appsobservatory_unlisted():
return render_template("unlistedapps.html", apps=apps) return render_template("unlistedapps.html", apps=apps)
@main.route('/app_maintainer_dash')
def app_maintainer_dash():
maintainers = set()
apps = App.query.all()
for app in apps:
maintainers.update(app.maintainers)
for test in app.most_recent_tests_per_branch():
if test.branch.name == "stable":
app.ci_level = test.level
maintainers = sorted(maintainers, key=lambda m: m.lower())
apps = sorted(apps, key=lambda app: app.name.lower())
return render_template("maintainer.html", maintainers=maintainers, apps=apps)

View file

@ -70,6 +70,7 @@ class AppList(db.Model):
known_app.maintainers = [ maintainer["name"] for maintainer in maintainers_info ] known_app.maintainers = [ maintainer["name"] for maintainer in maintainers_info ]
known_app.maintained = app.get("maintained", True) known_app.maintained = app.get("maintained", True)
known_app.state = app["state"]
known_app.ci_enabled = app["state"] == self.state_for_ci known_app.ci_enabled = app["state"] == self.state_for_ci
known_app.public_level = app.get("level", None) known_app.public_level = app.get("level", None)
@ -78,20 +79,18 @@ class AppList(db.Model):
known_app.public_commit = app["git"]["revision"] known_app.public_commit = app["git"]["revision"]
known_app.master_commit = g.commit(known_app, "master") known_app.master_commit = g.commit(known_app, "master")
known_app.public_commit_date = g.commit_date(known_app, known_app.public_commit)
known_app.master_commit_date = g.commit_date(known_app, known_app.master_commit)
known_app.testing_diff = g.diff(known_app, "master", "testing")["ahead_by"] known_app.testing_diff = g.diff(known_app, "master", "testing")["ahead_by"]
known_app.opened_issues = issues_and_prs["nb_issues"] known_app.opened_issues = issues_and_prs["nb_issues"]
known_app.opened_prs = issues_and_prs["nb_prs"] known_app.opened_prs = issues_and_prs["nb_prs"]
known_app.public_vs_master_time_diff = \
(g.commit_date(known_app, known_app.master_commit) -
g.commit_date(known_app, known_app.public_commit)).days
else: else:
known_app.public_commit = "???" known_app.public_commit = "???"
known_app.master_commit = "???" known_app.master_commit = "???"
known_app.testing_diff = -1 known_app.testing_diff = -1
known_app.opened_issues = 0 known_app.opened_issues = 0
known_app.opened_prs = 0 known_app.opened_prs = 0
known_app.public_vs_master_time_diff = 0
try: try:
db.session.commit() db.session.commit()
@ -106,6 +105,7 @@ class App(db.Model):
repo = db.Column(db.String(128), unique=True, nullable=False) repo = db.Column(db.String(128), unique=True, nullable=False)
maintainers = db.Column(db.PickleType) maintainers = db.Column(db.PickleType)
maintained = db.Column(db.Boolean, nullable=False) maintained = db.Column(db.Boolean, nullable=False)
state = db.Column(db.String(64), nullable=False)
ci_enabled = db.Column(db.Boolean, nullable=False) ci_enabled = db.Column(db.Boolean, nullable=False)
public_level = db.Column(db.Integer, default=-1, nullable=True) public_level = db.Column(db.Integer, default=-1, nullable=True)
@ -115,10 +115,11 @@ class App(db.Model):
# 'Status info' stuff # 'Status info' stuff
public_commit = db.Column(db.String(64), nullable=False) public_commit = db.Column(db.String(64), nullable=False)
master_commit = db.Column(db.String(64), nullable=False) master_commit = db.Column(db.String(64), nullable=False)
public_commit_date = db.Column(db.DateTime, nullable=True)
master_commit_date = db.Column(db.DateTime, nullable=True)
testing_diff = db.Column(db.Integer, default=-1) testing_diff = db.Column(db.Integer, default=-1)
opened_issues = db.Column(db.Integer, default=-1) opened_issues = db.Column(db.Integer, default=-1)
opened_prs = db.Column(db.Integer, default=-1) opened_prs = db.Column(db.Integer, default=-1)
public_vs_master_time_diff = db.Column(db.Integer, default=9999)
def __repr__(self): def __repr__(self):
return '<App %r>' % self.name return '<App %r>' % self.name
@ -126,9 +127,13 @@ class App(db.Model):
def init(): def init():
pass pass
@property
def public_vs_master_time_diff(self):
return (self.public_commit_date - self.master_commit_date).days
def most_recent_tests_per_branch(self): def most_recent_tests_per_branch(self):
from appci import AppCIBranch, AppCIResult, AppCI from app.models.appci import AppCIBranch, AppCIResult, AppCI
branches = AppCIBranch.query.all() branches = AppCIBranch.query.all()
for branch in branches: for branch in branches:
most_recent_test = AppCIResult.query \ most_recent_test = AppCIResult.query \

View file

@ -50,6 +50,9 @@
<a class="dropdown-item" href="{{ url_for('main.appsobservatory_unlisted')}}">Unlisted apps</a> <a class="dropdown-item" href="{{ url_for('main.appsobservatory_unlisted')}}">Unlisted apps</a>
</div> </div>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.app_maintainer_dash') }}">App maintainer dashboard</span></a>
</li>
</ul> </ul>
</div> </div>
</nav> </nav>

View file

@ -0,0 +1,187 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="mx-auto">
<select id="maintainer-select">
<option value="all">All</option>
<option value="nobody">Nobody / Unmaintained</option>
{% for maintainer in maintainers %}
<option value="{{ maintainer.lower()|replace(" ", "") }}">{{ maintainer }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<div class="mx-auto">
<div>
<table class="table table-responsive ci-app-table">
<thead>
<tr>
<th class="ci-app-row-title">App</th>
<th class="ci-app-test-title"><div>Declared state</div></th>
<th class="ci-app-test-title"><div>Maintained</div></th>
<th class="ci-app-test-title"><div>Public level</div></th>
<th class="ci-app-test-title"><div>CI level</div></th>
<th class="ci-app-test-title"><div># opened issues</div></th>
<th class="ci-app-test-title"><div># opened PR</div></th>
<th class="ci-app-test-title"><div>Last commit</div></th>
<th></th>
</tr>
</thead>
<tbody>
{% for app in apps %}
<tr class="appline" app="{{ app.name }}" maintainers="{% for m in app.maintainers %}{{ m.lower()|replace(" ", "") }}|{% endfor %}" maintained="{{ app.maintained }}">
<td class="ci-app-row-title">
<a href="{{ url_for('main.appci_app', app=app.name) }}">
<span class="font-weight-bold" title="More tests / info for this app">
{{ app.name }}</span>
</a>
</td>
<td>
{% if app.list.name == "official" %}
<span class="official-star oi oi-star" title="Official" aria-hidden="true"></span>
{% elif app.state == "working" %}
<span class="text-success oi oi-circle-check" title="Working" aria-hidden="true"></span>
{% elif app.state == "inprogress" %}
<span class="text-warning oi oi-wrench" title="In progress" aria-hidden="true"></span>
{% else %}
<span class="text-danger oi oi-fire" title="Not working" aria-hidden="true"></span>
{% endif %}
</td>
{% if app.maintained %}
<td class="text-success">
<span class="oi oi-circle-check" aria-hidden="true"></span>
{% else %}
<td class="text-warning">
<span class="oi oi-warning" aria-hidden="true"></span>
{% endif %}
</td>
{% if app.state == "inprogress" or app.state == "notworking" %}
<td class="ci-app-level"><div title="Public Level"></div></td>
<td class="ci-app-level"><div title="CI Level"></div></td>
{% else %}
<td class="ci-app-level
{% if app.public_level == None or app.public_level == -1 or app.public_level == "?" %}
table-active
{% elif app.public_level <= 0 %}
table-danger
{% elif app.public_level <= 2 %}
table-warning
{% else %}
table-success
{% endif %}
" value="{{ app.public_level }}">
<div title="Public Level"><strong>{{ app.public_level if app.public_level >= 0 else "?" }}</strong></div>
</td>
<td class="ci-app-level
{% if app.ci_level == None or app.ci_level == -1 or app.ci_level == "?" %}
table-active
{% elif app.ci_level <= 0 %}
table-danger
{% elif app.ci_level <= 2 %}
table-warning
{% else %}
table-success
{% endif %}
" value="{{ app.ci_level }}">
<div title="CI Level"><strong>{{ app.ci_level if app.ci_level and app.ci_level >= 0 else "?" }}</strong></div>
</td>
{% endif %}
<td class="font-weight-bold
{% if app.opened_issues >= 10 %}
text-danger
{% elif app.opened_issues >= 5 %}
text-warning
{% elif app.opened_issues > 0 %}
text-active
{% else %}
text-success
{% endif %}
">{{ app.opened_issues }}</a></td>
<td class="font-weight-bold
{% if app.opened_prs > 0 %}
text-info
{% endif %}
">{{ app.opened_prs }}</td>
<td class="ci-app-test-info">
{% if app.public_commit_date %}
<span class="daysAgo" timestamp={{ app.public_commit_date.timestamp() }}></span></td>
{% else %}
<span class="daysAgo">???</span></td>
{% endif %}
</td>
<td class="px-0">
<a href="{{ app.repo }}">
<span class="oi oi-external-link text-info"
aria-hidden="true"
title="To the Git repo!"></span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script>
window.onload = function () {
$('#maintainer-select').on('change', function() {
var maintainer = this.value;
if (maintainer == "all")
{
$(".appline").show();
return;
}
else if (maintainer == "nobody")
{
$(".appline").each(function (i) {
if ((this.attributes["maintainers"].value == "") || (this.attributes["maintained"].value == "False"))
{
$(this).show();
}
else {
$(this).hide();
}
});
}
else
{
$(".appline").each(function (i) {
var maintainers = this.attributes["maintainers"].value.split("|");
if (maintainers.includes(maintainer)) {
$(this).show();
}
else {
$(this).hide();
}
});
}
});
}
</script>
{% endblock %}