Skip to content

Commit

Permalink
add example with an http requests and a line chart
Browse files Browse the repository at this point in the history
  • Loading branch information
tardyp committed Mar 16, 2017
1 parent 50bc2be commit e959224
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 123 deletions.
83 changes: 4 additions & 79 deletions master/docs/manual/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -990,93 +990,18 @@ There is a Buildbot plugin which allows to write a server side generated dashboa
Here is an example of code that you can use in your master.cfg to create a simple dashboard:


.. Following code is tested in smokes/master.cfg. Please do not make modification here without modifying also that master.cfg!

.. code-block:: python
.. literalinclude:: mydashboard.py
:language: python

from flask import Flask, render_template
mydashboardapp = Flask('test', root_path=os.path.dirname(__file__))
# this allows to work on the template without having to restart Buildbot
mydashboardapp.config['TEMPLATES_AUTO_RELOAD'] = True
@mydashboardapp.route("/index.html")
def main():
# This code fetches build data from the data api, and give it to the template
builders = mydashboardapp.buildbot_api.dataGet("/builders")
builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20)
# properties are actually not used in the template example, but this is how you get more properties
for build in builds:
build['properties'] = mydashboardapp.buildbot_api.dataGet(("builds", build['buildid'], "properties"))
# mydashboard.html is a template inside the template directory
return render_template('mydashboard.html', builders=builders, builds=builds)
# Here we assume c['www']['plugins'] has already be created earlier.
# Please see the web server documentation to understand how to configure the other parts.
c['www']['plugins']['wsgi_dashboards'] = [ # This is a list of dashboards, you can create several
{
'name': 'mydashboard', # as used in URLs
'caption': 'My Dashboard', # Title displayed in the UI'
'app': mydashboardapp,
'order': 5, # priority of the dashboard in the left menu (lower is higher in the menu)
'icon': 'area-chart' # available icon list can be found at http://fontawesome.io/icons/
}
]

Then you need a ``templates/mydashboard.html`` file near your ``master.cfg``.

This template is a standard Jinja_ template which is the default templating engine of Flask_.

.. code-block:: html

<div class="container">
<table class="table">
<tr>
{% for builder in builders %}
<th>
{{builder.name}}
</th>
{% endfor %}
</tr>
{% for build in builds %}
<tr>
{% for builder in builders %}
<th>
{% if build.builderid == builder.builderid %}
<a class="badge-status badge results_{{build.results_text|upper}}" href="#/builders/{{build.builderid}}/builds/{{build.number}}">
{{build.number}}
</a>
{% endif %}
</th>
{% endfor %}
</tr>
{% endfor %}
</table>
</div>

You can use the buildsummary directive by replacing the following code in the previous template:

.. code-block:: html

<a class="badge-status badge results_{{build.results_text|upper}}" href="#/builders/{{build.builderid}}/builds/{{build.number}}">
{{build.number}}

by:

.. code-block:: html

<buildsummary buildid="{{build.buildid}}" condensed="1"/>

The buildsummary directive is very powerful and will display steps, sub-builds, logs, urls.
If you need something lighter, there is the build sticker directive:

.. code-block:: html

<buildsticker buildid="{{build.buildid}}"/>
.. literalinclude:: mydashboard.html
:language: html

Note that those two directives will make additional HTTP requests from the browser in order to fetch the necessary data they need to be rendered.

.. _Flask: http://flask.pocoo.org/
.. _Bottle: https://bottlepy.org/docs/dev/
Expand Down
1 change: 1 addition & 0 deletions master/docs/manual/mydashboard.html
1 change: 1 addition & 0 deletions master/docs/manual/mydashboard.py
39 changes: 1 addition & 38 deletions smokes/master.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
from __future__ import absolute_import
from __future__ import print_function

import os

from buildbot.plugins import *
from flask import Flask
from flask import render_template

# This is a sample buildmaster config file. It must be installed as
# 'master.cfg' in your buildmaster's base directory.
Expand Down Expand Up @@ -107,8 +103,6 @@ c['titleURL'] = "https://launchpad.net/pyflakes"

c['buildbotURL'] = "http://localhost:8010/"



# minimalistic config to activate new web UI
c['www'] = dict(port=8010,
change_hook_dialects={'base': True},
Expand All @@ -121,35 +115,4 @@ c['db'] = {
# this at its default for all but the largest installations.
'db_url': "sqlite:///state.sqlite",
}


mydashboardapp = Flask('test', root_path=os.path.dirname(__file__))
# this allows to work on the template without having to restart Buildbot
mydashboardapp.config['TEMPLATES_AUTO_RELOAD'] = True


@mydashboardapp.route("/index.html")
def main():
# This code fetches build data from the data api, and give it to the template
builders = mydashboardapp.buildbot_api.dataGet("/builders")

builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20)

# properties are actually not used in the template example, but this is how you get more properties
for build in builds:
build['properties'] = mydashboardapp.buildbot_api.dataGet(("builds", build['buildid'], "properties"))

# mydashboard.html is a template inside the template directory
return render_template('mydashboard.html', builders=builders, builds=builds)

# Here we assume c['www']['plugins'] has already be created earlier.
# Please see the web server documentation to understand how to configure the other parts.
c['www']['plugins']['wsgi_dashboards'] = [ # This is a list of dashboards, you can create several
{
'name': 'mydashboard', # as used in URLs
'caption': 'My Dashboard', # Title displayed in the UI'
'app': mydashboardapp,
'order': 5, # priority of the dashboard in the left menu (lower is higher in the menu)
'icon': 'area-chart' # available icon list can be found at http://fontawesome.io/icons/
}
]
exec(open("mydashboard.py").read())
58 changes: 58 additions & 0 deletions smokes/mydashboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import absolute_import
from __future__ import print_function

import os
import time

import requests

from flask import Flask
from flask import render_template

mydashboardapp = Flask('test', root_path=os.path.dirname(__file__))
# this allows to work on the template without having to restart Buildbot
mydashboardapp.config['TEMPLATES_AUTO_RELOAD'] = True


@mydashboardapp.route("/index.html")
def main():
# This code fetches build data from the data api, and give it to the template
builders = mydashboardapp.buildbot_api.dataGet("/builders")

builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20)

# properties are actually not used in the template example, but this is how you get more properties
for build in builds:
build['properties'] = mydashboardapp.buildbot_api.dataGet(("builds", build['buildid'], "properties"))

# Example on how to use requests to get some info from other web servers
code_frequency_url = "https://api.github.com/repos/buildbot/buildbot/stats/code_frequency"
results = requests.get(code_frequency_url)
while results.status_code == 202:
# while github calculates statistics, it returns code 202.
# this is no problem, we just sleep in our thread..
time.sleep(500)
results = requests.get(code_frequency_url)

# some post processing of the data from github
graph_data = []
for i, data in enumerate(results.json()):
graph_data.append(
dict(x=data[0], y=data[1])
)

# mydashboard.html is a template inside the template directory
return render_template('mydashboard.html', builders=builders, builds=builds,
graph_data=graph_data)

# Here we assume c['www']['plugins'] has already be created earlier.
# Please see the web server documentation to understand how to configure the other parts.
c['www']['plugins']['wsgi_dashboards'] = [ # This is a list of dashboards, you can create several
{
'name': 'mydashboard', # as used in URLs
'caption': 'My Dashboard', # Title displayed in the UI'
'app': mydashboardapp,
'order': 5, # priority of the dashboard in the left menu (lower is higher in the menu)
'icon': 'area-chart' # available icon list can be found at http://fontawesome.io/icons/
}
]
2 changes: 1 addition & 1 deletion smokes/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -v
cd `dirname $0`
rm -rf workdir
buildbot create-master workdir
cp -r templates master.cfg workdir
ln -s ../templates ../mydashboard.py ../master.cfg workdir
buildbot-worker create-worker workdir/worker localhost example-worker pass
buildbot checkconfig workdir
# on docker buildbot might be a little bit slower to start, so sleep another 20s in case of start to slow.
Expand Down
49 changes: 44 additions & 5 deletions smokes/templates/mydashboard.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<div class="container">
<!-- Create a table of builds organised by builders in columns -->
<table class="table">
<tr>
<!-- Generate the table header with name of builders -->
{% for builder in builders %}
<th>
{{builder.name}}
Expand All @@ -11,16 +13,53 @@
<tr>
{% for builder in builders %}
<th>
<!-- If this build is from this builderid, then we render it in this cell -->
{% if build.builderid == builder.builderid %}
<a class="badge-status badge results_{{build.results_text|upper}}" href="#/builders/{{build.builderid}}/builds/{{build.number}}">
{{build.number}}
</a>
<buildsummary buildid="{{build.buildid}}" condensed="1"/>
<buildsticker buildid="{{build.buildid}}"/>
<!-- for representing a build, you can choose one of those three forms -->
<!-- 1) We use buildbot internal CSS styles display our builds, with links to the standard UI -->
<a class="badge-status badge results_{{build.results_text | upper}}" href="#/builders/{{build.builderid}}/builds/{{build.number}}">
{{build.number}}
</a>
<!-- 2) The buildsummary directive is very powerful and will display steps, sub-builds, logs, urls. -->
<buildsummary buildid="{{build.buildid}}" condensed="1"/>
<!-- 3) If you need something lighter, there is the build sticker directive -->
<buildsticker buildid="{{build.buildid}}"/>
<!-- Note that those two directives will make additional HTTP requests from the browser in order to fetch the necessary data they need to be rendered. -->

{% endif %}
</th>
{% endfor %}
</tr>
{% endfor %}
</table>
<!-- Example of line chart using Chart.js -->
<canvas id="myChart" width="400" height="400"></canvas>
<script>
// We use Chart.js for rendering a chart, we first have to download it from internet
// (will be cached by the browser)
$.getScript("https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js",
// See http://www.chartjs.org/docs/ for more details
function createChart() {
var scatterChart = new Chart("myChart", {
type: 'line',
data: {
datasets: [{
label: 'Github statistics',
// Here the data from the python is passed to the javascript via tojson and safe jinja filters
// http://flask.pocoo.org/docs/0.12/templating/#standard-filters
data: {{graph_data | tojson |safe }}
}]
},
options: {
scales: {
xAxes: [{
type: 'linear',
position: 'bottom'
}]
}
}
});
});
</script>

</div>

0 comments on commit e959224

Please sign in to comment.