mirror of
https://github.com/YunoHost/tartiflette.git
synced 2024-09-03 20:06:08 +02:00
Adding roadmapProgressBar as a dirty subfolder
This commit is contained in:
parent
f7d624d068
commit
8a70a4216e
5 changed files with 302 additions and 0 deletions
90
roadmapProgressBar/analyze.py
Executable file
90
roadmapProgressBar/analyze.py
Executable file
|
@ -0,0 +1,90 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
|
||||||
|
status_filters = {
|
||||||
|
"all": None,
|
||||||
|
"new": ["New", "Confirmed"],
|
||||||
|
"ongoing": ["In Progress"],
|
||||||
|
"done": ["Closed", "Resolved", "Rejected"]
|
||||||
|
}
|
||||||
|
|
||||||
|
type_filters = {
|
||||||
|
"all": None,
|
||||||
|
"Bug": "Bug",
|
||||||
|
"Feature": "Feature",
|
||||||
|
"Improve": "Improvement",
|
||||||
|
"Doc": "Documentation"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def parse_issues():
|
||||||
|
|
||||||
|
soup = BeautifulSoup(open("data/raw_roadmapissues.xml").read(), "lxml")
|
||||||
|
|
||||||
|
issues = []
|
||||||
|
|
||||||
|
for issue in soup.issues:
|
||||||
|
cleaned_issue = {}
|
||||||
|
cleaned_issue["id"] = issue.id.text
|
||||||
|
cleaned_issue["priority"] = issue.priority["name"]
|
||||||
|
cleaned_issue["status"] = issue.status["name"]
|
||||||
|
cleaned_issue["type"] = issue.tracker["name"]
|
||||||
|
|
||||||
|
issues.append(cleaned_issue)
|
||||||
|
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
def filtered_issues(issues, status_filter=None, type_filter=None):
|
||||||
|
|
||||||
|
issues_filtered = issues
|
||||||
|
if status_filter != None:
|
||||||
|
issues_filtered = [ issue for issue in issues_filtered if issue["status"] in status_filter]
|
||||||
|
|
||||||
|
if type_filter != None:
|
||||||
|
issues_filtered = [ issue for issue in issues_filtered if issue["type"] == type_filter ]
|
||||||
|
|
||||||
|
return len(issues_filtered)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
issues = parse_issues()
|
||||||
|
summary = {}
|
||||||
|
|
||||||
|
for type_name, type_filter in type_filters.items():
|
||||||
|
|
||||||
|
summary[type_name] = {}
|
||||||
|
|
||||||
|
for status_name, status_filter in status_filters.items():
|
||||||
|
|
||||||
|
summary[type_name][status_name] = filtered_issues(issues, status_filter,
|
||||||
|
type_filter)
|
||||||
|
|
||||||
|
for type_name, type_filter in type_filters.items():
|
||||||
|
|
||||||
|
for status_name, status_filter in status_filters.items():
|
||||||
|
|
||||||
|
if (status_name != "all"):
|
||||||
|
|
||||||
|
n = summary[type_name][status_name]
|
||||||
|
p = float("{0:.1f}".format(100 * n / summary[type_name]["all"]))
|
||||||
|
summary[type_name][status_name] = (n,p)
|
||||||
|
|
||||||
|
if (type_name != "all"):
|
||||||
|
n = summary[type_name]["all"]
|
||||||
|
p = float("{0:.1f}".format(100 * n / summary["all"]["all"]))
|
||||||
|
summary[type_name]["all"] = (n,p)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
with open("summary.json", "w") as f:
|
||||||
|
f.write(json.dumps(summary))
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
0
roadmapProgressBar/data/.gitkeep
Normal file
0
roadmapProgressBar/data/.gitkeep
Normal file
14
roadmapProgressBar/fetch.py
Executable file
14
roadmapProgressBar/fetch.py
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
def get_roadmapissues():
|
||||||
|
|
||||||
|
roadmapissues = requests.get("https://dev.yunohost.org/issues.xml?fixed_version_id=11&status_id=*&limit=100")
|
||||||
|
|
||||||
|
|
||||||
|
with open("data/raw_roadmapissues.xml", "w") as f:
|
||||||
|
f.write(roadmapissues.text)
|
||||||
|
|
||||||
|
get_roadmapissues()
|
44
roadmapProgressBar/publish.py
Executable file
44
roadmapProgressBar/publish.py
Executable 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
|
||||||
|
|
||||||
|
summary = json.load(open(summary_path))
|
||||||
|
|
||||||
|
# Generate the output using the template
|
||||||
|
|
||||||
|
template = open(template_path, "r").read()
|
||||||
|
t = Template(template)
|
||||||
|
|
||||||
|
result = t.render(data=summary, convert=shell_to_html, shell_css=shell_css)
|
||||||
|
|
||||||
|
open(output_path, "w").write(result)
|
||||||
|
|
||||||
|
print("Done.")
|
154
roadmapProgressBar/www/template.html
Normal file
154
roadmapProgressBar/www/template.html
Normal 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>Yunohost Pull Requests Dashboard</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;
|
||||||
|
}
|
||||||
|
.progress .progress-bar {
|
||||||
|
padding-top:5px;
|
||||||
|
font-size:16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.progress-bar-none {
|
||||||
|
background-color:transparent;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
.issue-legend {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom:20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<div class="page-header" id="banner">
|
||||||
|
<div class="row">
|
||||||
|
<h1>Yunohost Roadmap Dashboard</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>2.6.x</h3>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-md-offset-1 col-md-10">
|
||||||
|
|
||||||
|
<div class="issue-legend">All ({{data.all.all}} issues) </div>
|
||||||
|
<div class="bs-component">
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar progress-bar-success" style="width:
|
||||||
|
{{data.all.done[1]}}%">{{data.all.done[0]}} done</div>
|
||||||
|
<div class="progress-bar progress-bar-warning" style="width:
|
||||||
|
{{data.all.ongoing[1]}}%">{{data.all.ongoing[0]}}
|
||||||
|
ongoing</div>
|
||||||
|
<div class="progress-bar progress-bar-none" style="width:
|
||||||
|
{{data.all.new[1]}}%">{{data.all.new[0]}} new</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for type, statuses in data.items() %}
|
||||||
|
{% if type != "all" %}
|
||||||
|
<div class="bs-component" style="display:inline-block; width: {{
|
||||||
|
statuses.all[1]-0.5 }}%" >
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar progress-bar-success" style="width: {{statuses.done[1]}}%">
|
||||||
|
{{ statuses.done[0] }}
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar progress-bar-warning" style="width: {{statuses.ongoing[1]}}%">
|
||||||
|
{{ statuses.ongoing[0] }}
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar progress-bar-none" style="width:
|
||||||
|
{{statuses.new[1]}}%">
|
||||||
|
{{ statuses.new[0] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="issue-legend">{{ type }}<br> ({{ statuses.all[0]
|
||||||
|
}})</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-offset-1 col-md-10">
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function filter(team) {
|
||||||
|
// Declare variables
|
||||||
|
var input, filter, table, tr, td, i;
|
||||||
|
table = document.getElementById("thePRlist");
|
||||||
|
tr = table.getElementsByTagName("tr");
|
||||||
|
// Loop through all table rows, and hide those who don't match the search query
|
||||||
|
for (i = 0; i < tr.length; i++)
|
||||||
|
{
|
||||||
|
if (team == '') { tr[i].style.display = ""; }
|
||||||
|
else if (tr[i].classList == "") { tr[i].style.display = ""; }
|
||||||
|
else if (tr[i].classList.contains(team)) { tr[i].style.display = ""; }
|
||||||
|
else { tr[i].style.display = "none"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
selector = document.getElementById("select-team");
|
||||||
|
li = selector.getElementsByTagName("li");
|
||||||
|
|
||||||
|
if (team == "") { team = "team-all"; }
|
||||||
|
|
||||||
|
for (i = 0; i < li.length; i++)
|
||||||
|
{
|
||||||
|
if (li[i].getAttribute("id") == "select-".concat(team))
|
||||||
|
{
|
||||||
|
li[i].classList.add("active");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
li[i].classList.remove("active");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue