Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scorecard: Use Sanic, cache fully-shaped GitHub response #5242

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scorecard/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ FROM continuumio/miniconda
MAINTAINER Hail Team <[email protected]>

COPY environment.yml .
RUN apt-get update && apt-get install -y linux-headers-amd64 build-essential
RUN conda env create scorecard -f environment.yml && \
rm -f environment.yml && \
rm -rf /home/root/.conda/pkgs/*
Expand Down
5 changes: 3 additions & 2 deletions scorecard/environment.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name: scorecard
dependencies:
- python=3.7
- flask
- flask-cors
- humanize
- pip
- jinja2
- pip:
- PyGithub
- sanic
- sanic-cors
54 changes: 37 additions & 17 deletions scorecard/scorecard/scorecard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
import datetime
import os
import sys
from flask import Flask, render_template, request, jsonify, abort, url_for
from flask_cors import CORS
from github import Github
import random
import threading
import humanize
import logging
import ujson # included by Sanic
from sanic import Sanic
from sanic.response import text,json,html
from sanic_cors import CORS
from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(loader=PackageLoader('scorecard', 'templates/'), autoescape=select_autoescape(['html', 'xml', 'tpl']), enable_async=True)

users_template = env.get_template('index.html')
one_user_templ = env.get_template('user.html')

fmt = logging.Formatter(
# NB: no space after levename because WARNING is so long
Expand Down Expand Up @@ -55,44 +63,51 @@
'cloudtools': 'Nealelab/cloudtools'
}

app = Flask('scorecard')
app = Sanic(__name__)
CORS(app, resources={r'/json/*': {'origins': '*'}})

data = None
users_data = None
users_json = None
rendered_users_template = None
timsetamp = None

@app.route('/')
def index():
user_data, unassigned, urgent_issues, updated = get_users()
async def index(request):
user_data, unassigned, urgent_issues, updated = users_data

random_user = random.choice(users)

return render_template('index.html', unassigned=unassigned,
tmpl = await users_template.render_async( unassigned=unassigned,
user_data=user_data, urgent_issues=urgent_issues, random_user=random_user, updated=updated)
return html(tmpl)

@app.route('/users/<user>')
def html_get_user(user):
async def html_get_user(request, user):
user_data, updated = get_user(user)
return render_template('user.html', user=user, user_data=user_data, updated=updated)

tmpl = await one_user_templ.render_async(user=user, user_data=user_data, updated=updated)
return html(tmpl)

@app.route('/json')
def json_all_users():
user_data, unassigned, urgent_issues, updated = get_users()
async def json_all_users(request):
user_data, unassigned, urgent_issues, updated = users_data

for issue in urgent_issues:
issue['timedelta'] = humanize.naturaltime(issue['timedelta'])

return jsonify(updated=updated, user_data=user_data, unassigned=unassigned, urgent_issues=urgent_issues)
return text(users_json)

@app.route('/json/users/<user>')
def json_user(user):
async def json_user(request,user):
user_data, updated = get_user(user)
return jsonify(updated=updated, data=user_data)
return json({"updated": updated, "user_data": user_data})

@app.route('/json/random')
def json_random_user():
return jsonify(random.choice(users))
async def json_random_user(request):
return text(random.choice(users))

# Lets cache this; we now call this only during update
def get_users():
cur_data = data
cur_timestamp = timestamp
Expand Down Expand Up @@ -236,7 +251,7 @@ def get_issue_data(repo_name, issue):
}

def update_data():
global data, timestamp
global data, timestamp, users_data, users_json

log.info(f'rate_limit {github.get_rate_limit()}')
log.info('start updating_data')
Expand Down Expand Up @@ -269,6 +284,11 @@ def update_data():
data = new_data
timestamp = now

# Takes reference, so don't mutate data
# user_data, unassigned, urgent_issues, updated = users_data
users_data = get_users()
users_json = ujson.dumps({"user_data": users_data[0], "unassigned": users_data[1], "urgent_issues": users_data[2], "updated": users_data[3]})

def poll():
while True:
time.sleep(180)
Expand Down Expand Up @@ -301,4 +321,4 @@ def run_forever(target, *args, **kwargs):
poll_thread.start()

if __name__ == '__main__':
app.run(host='0.0.0.0')
app.run(host='0.0.0.0', port=5000)
1 change: 1 addition & 0 deletions scorecard/scorecard/templates/index.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<html lang="en">
<head>
<title>Scorecard</title>
<link rel="shortcut icon" href="#" />
<style type="text/css">
td {
padding: 3px 10px 3px 10px;
Expand Down
98 changes: 55 additions & 43 deletions scorecard/scorecard/templates/user.html
Original file line number Diff line number Diff line change
@@ -1,48 +1,56 @@
<html lang="en">
<head>
<head>
<title>Scorecard: User {{ user }}</title>
<link rel="shortcut icon" href="#" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again add the favicon fix. The rest is HTML formatting, not critical if you prefer the style you already had

<style type="text/css">
td { padding: 0 20px 0 0; }
th { padding: 0 20px 0 0; }
td {
padding: 0 20px 0 0;
}
th {
padding: 0 20px 0 0;
}

#avatar {
float: left;
width: 44px;
height: 44px;
margin: 0 8px 0 0;
border-radius: 3px;
float: left;
width: 44px;
height: 44px;
margin: 0 8px 0 0;
border-radius: 3px;
}
.grid-container {
display: inline-grid;
grid-template-columns: auto auto;
display: inline-grid;
grid-template-columns: auto auto;
}
body {
font-family: 'Lucida Sans Unicode', 'Lucida Grande', sans-serif;
}
body {
font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
}

</style>
</head>
<body>
<div class="grid-container">
<div class="grid-item">
<p><img id="avatar" src="https://github.com/{{ user }}.png?s=88"></p>
</div>
</head>
<body>
<div class="grid-container">
<div class="grid-item">
<p><img id="avatar" src="https://github.com/{{ user }}.png?s=88" /></p>
</div>

<div class="grid-item">
<div class="grid-item">
<p>Welcome to Scorecard, {{ user }}!</p>

<h3>Needs Review</h3>
{% if user_data['NEEDS_REVIEW'] %}
<table>
<tbody>
<tbody>
{% for pr in user_data['NEEDS_REVIEW'] %}
<tr>
<td><a href="{{ pr.html_url }}">{{ pr.id }}</a></td>
<td><a href="https://github.com/{{ pr.user }}">{{ pr.user }}</a></td>
<td>{{ pr.title }}</td>
<td>
<a href="{{ pr.html_url }}">{{ pr.id }}</a>
</td>
<td>
<a href="https://github.com/{{ pr.user }}">{{ pr.user }}</a>
</td>
<td>{{ pr.title }}</td>
</tr>
{% endfor %}
</tbody>
</tbody>
</table>
{% else %}
<p>No reviews needed.</p>
Expand All @@ -51,14 +59,16 @@ <h3>Needs Review</h3>
<h3>Changes Requested</h3>
{% if user_data['CHANGES_REQUESTED'] %}
<table>
<tbody>
<tbody>
{% for pr in user_data['CHANGES_REQUESTED'] %}
<tr>
<td><a href="{{ pr.html_url }}">{{ pr.id }}</a></td>
<td>{{ pr.title }}</td>
<td>
<a href="{{ pr.html_url }}">{{ pr.id }}</a>
</td>
<td>{{ pr.title }}</td>
</tr>
{% endfor %}
</tbody>
</tbody>
</table>
{% else %}
<p>No changes requested.</p>
Expand All @@ -67,41 +77,43 @@ <h3>Changes Requested</h3>
<h3>Failing tests</h3>
{% if user_data['FAILING'] %}
<table>
<tbody>
<tbody>
{% for pr in user_data['FAILING'] %}
<tr>
<td><a href="{{ pr.html_url }}">{{ pr.id }}</a></td>
<td>{{ pr.title }}</td>
<td>
<a href="{{ pr.html_url }}">{{ pr.id }}</a>
</td>
<td>{{ pr.title }}</td>
</tr>
{% endfor %}
</tbody>
</tbody>
</table>
{% else %}
<p>No failing builds.</p>
{% endif %}


<h3>Issues</h3>
{% if user_data['ISSUES'] %}
<table>
<tbody>
<tbody>
{% for issue in user_data['ISSUES'] %}
<tr>
<td><a href="{{ issue.html_url }}">{{ issue.id }}</a></td>
<td>{{ issue.title }}</td>
<td>
<a href="{{ issue.html_url }}">{{ issue.id }}</a>
</td>
<td>{{ issue.title }}</td>
</tr>
{% endfor %}
</tbody>
</tbody>
</table>
{% else %}
<p>No issues.</p>
{% endif %}

<p>
<small>last updated {{ updated }}</small>
<small>last updated {{ updated }}</small>
</p>
</div>
</div>
</div>

</body>
</body>
</html>