Initial commit

This commit is contained in:
Alexandre Aubin 2017-03-08 08:24:58 -05:00
commit 56aa387b5d
5 changed files with 339 additions and 0 deletions

32
README.md Normal file
View file

@ -0,0 +1,32 @@
Aiguillette
===========
A quick and dirty PR dashboard using Eden UI
Install
-------
- Clone this repo
- Download and unzip Eden UI into www : http://scripteden.com/download/eden-ui-bootstrap-3-skin/
- Install dependencies :
```
apt install -y python3-pip
pip3 install ansi2html
```
- Make your web browser serve www/index.html
Usage
-----
```
./fetch.py
./analyze.py
./publish.py
```
- Edit fetch.py and analyze.py to custom list of repo to fetch (should be moved
to a central conf file)
- Don't know the number of API calls someone is allowed to do, so limit the call
to fetch.py :/
- Everything is pretty dirty so far and should be cleaned

91
analyze.py Executable file
View file

@ -0,0 +1,91 @@
#!/usr/bin/python3
import json
import datetime
repos = ["yunohost", "yunohost-admin", "SSOwat", "moulinette", "doc", "ynh-dev",
"apps", "CI_package_check", "example_ynh", "package_linter", "Simone",
"project-organization", "build.yunohost.org", "dynette", "YunoPorts",
"rebuildd", "cd_build", "install_script"]
prs = {}
def githubDateToDaysAgo(date):
now = datetime.datetime.now()
date = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
return (now - date).days
def isPRDying(pr):
return (pr["createdDaysAgo"] > 60 and pr["updatedDaysAgo"] > 30)
def priority(pr):
if "important" in pr["labels"]:
base_priority = 100
elif "opinion needed" in pr["labels"]:
base_priority = 50
elif "work needed" in pr["labels"]:
base_priority = -50
elif "postponed" in pr["labels"]:
base_priority = -100
elif "inactive" in pr["labels"]:
base_priority = -100
else:
base_priority = 0
if "dying" in pr["labels"] and base_priority > -100:
base_priority += 5
return base_priority
def main():
for repo in repos:
print("Analyzing %s ..." % repo)
with open("./%s.json" % repo, "r") as f:
j = json.loads(f.read())
for issue in j:
# Ignore non-pullrequest issues
if "pull_request" not in issue.keys():
continue
pr = {
"repo": repo,
"title": issue["title"],
"labels": [label["name"] for label in issue["labels"]],
"id": "%s-%s" % (repo, issue["number"]),
"createdDaysAgo": githubDateToDaysAgo(issue["created_at"]),
"updatedDaysAgo": githubDateToDaysAgo(issue["updated_at"]),
"url": issue["pull_request"]["html_url"]
}
if len(pr["title"]) > 53:
pr["title"] = pr["title"][0:50] + "..."
if isPRDying(pr):
pr["labels"].append("dying")
pr["priority"] = priority(pr)
prs[pr["id"]] = pr
prs_sorted = sorted(prs.keys(), key=lambda x: (prs[x]["priority"],
prs[x]["createdDaysAgo"]), reverse=True )
summary = []
for name in prs_sorted:
summary.append(prs[name])
with open("summary.json", "w") as f:
f.write(json.dumps(summary))
main()

18
fetch.py Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/python3
import requests
repos = ["yunohost", "yunohost-admin", "SSOwat", "moulinette", "doc", "ynh-dev",
"apps", "CI_package_check", "example_ynh", "package_linter", "Simone",
"project-organization", "build.yunohost.org", "dynette", "YunoPorts",
"rebuildd", "cd_build", "install_script"]
for repo in repos:
print("Fetching pull requests for %s" % repo)
issues = requests.get("https://api.github.com/repos/yunohost/%s/issues?per_page=100" % repo)
with open("./%s.json" % repo, "w") as f:
f.write(issues.text)

44
publish.py Executable file
View file

@ -0,0 +1,44 @@
#!/usr/bin/python3
import os
import json
from jinja2 import Template
from ansi2html import Ansi2HTMLConverter
from ansi2html.style import get_styles
###############################################################################
output_dir = "./www/"
template_path = os.path.join(output_dir,"template.html")
output_path = os.path.join(output_dir,"index.html")
summary_path = os.path.join("./", "summary.json")
###############################################################################
conv = Ansi2HTMLConverter()
shell_css = "\n".join(map(str, get_styles(conv.dark_bg, conv.scheme)))
def shell_to_html(shell):
return conv.convert(shell, False)
###############################################################################
if __name__ == '__main__':
# Fetch the list of all reports, sorted in reverse-chronological order
pr_list = json.load(open(summary_path))
# Generate the output using the template
template = open(template_path, "r").read()
t = Template(template)
result = t.render(data=pr_list, convert=shell_to_html, shell_css=shell_css)
open(output_path, "w").write(result)
print("Done.")

154
www/template.html Normal file
View file

@ -0,0 +1,154 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Bootstrap Skin: Eden</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="css/bootstrap.css" media="screen">
<link rel="stylesheet" href="skins/eden.css" media="screen">
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet">
<link href="css/animate.css" rel="stylesheet">
<style>
.navbar-holder-dark{
padding: 20px 20px 200px 20px;
background: #333333;
}
.container {
width:1500px;
}
</style>
</head>
<body>
<div class="container">
<div class="page-header" id="banner">
<div class="row">
<h1>Yunohost Pull Requests Dashboard</h1>
</div>
</div>
<h3>WTF is this shit? How is priority defined?</h3>
<div class="row">
<div class="col-md-12">
First with labels :
<p>"important" implies top-priority ------
"opinion-needed" implies medium priority ------
"work needed" implies low priority ------
"inactive" / "postponed" implies very low priority.</p>
Then with creation time :
<p>older PRs have higher priority than newer PR</p>
'Dying' status
<p>A PR is considered "dying" if it has been created more than 60
days ago and not updated since 30 days. This is meant to be an incentive to
either revive it or flag it as inactive/postponed... 'Dying' PRs
have a small boost in priority to be listed first</a>
</br>
<p>Repos considered for now (completely arbitrary) : [yunohost, yunohost-admin, SSOwat, moulinette, doc, ynh-dev,
apps, CI_package_check, example_ynh, package_linter, Simone,
project-organization, build.yunohost.org, dynette, YunoPorts,
rebuildd, cd_build, install_script]</p>
</div>
</div>
<h3>What should you review ?</h3>
<div class="row">
<div class="col-md-offset-3 col-md-6">
<div class="bs-component">
<ul class="nav nav-pills">
<li class="active"><a href="#">All <span class="badge">1664</span></a></li>
<li><a href="#">Core <span class="badge">42</span></a></li>
<li><a href="#">Apps <span class="badge">42</span></a/li>
<li><a href="#">Infra / dist<span class="badge">42</span></a></li>
<li><a href="#">Doc / i18n<span class="badge">42</span></a></li>
</ul>
</div>
</div>
<div class="col-md-12">
<div>
<table class="table table-striped table-responsive">
<thead>
<tr>
<th></th>
<th>Title</th>
<th>Created</th>
<th>Labels</th>
<th>Reviews</th>
</tr>
</thead>
<tbody>
{% for pr in data %}
<tr>
<td><center><a class="btn
{% if pr.priority >= 100 %}btn-warning{% else %}
{% if pr.priority >= 50 %}btn-primary{% else %}
{% if pr.priority >= 0 %}btn-info{% else %}
{% if pr.priority >= -50 %}btn-default{% else %}
btn-link{% endif %}
{% endif %}
{% endif %}
{% endif %}"
href="{{ pr.url }}">{{ pr.id }}</a></center></td>
<td><strong>{{ pr.title }}</strong></td>
<td>{{ pr.createdDaysAgo }} days ago</td>
<td>
{% for label in pr.labels %}
<span class="label
{% if label == "important" %}label-danger{%endif%}
{% if label == "opinion needed" %}label-warning{%endif%}
{% if label == "small decision" %}label-info{%endif%}
{% if label == "medium decision" %}label-info{%endif%}
{% if label == "big decision" %}label-info{%endif%}
{% if label == "work needed" %}label-primary{%endif%}
{% if label == "inactive" %}label-default{%endif%}
{% if label == "postponed" %}label-default{%endif%}
{% if label == "dying" %}label-danger{%endif%}
">{{ label }}</span>
&nbsp;
{% endfor %}
</td>
<td>
<span style="border:1px solid black; border-radius:4px; padding-left:2px; padding-right:2px;">foo <span class="text-success"></span></span>
<span style="border:1px solid black; border-radius:4px; padding-left:2px; padding-right:2px;">bar <span class="text-danger" ></span></span>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="col-lg-12">
<hr/>
<p>CSS Skin/boilerplate/whatever you call it : <a href="http://scripteden.com/" rel="nofollow">Script Eden</a>.</p>
</div>
</div>
</footer>
</div>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html>