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

Standalone #365

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from all 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 .gitignore
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@
.coverage
*.pyc
reports
tests/media


10 changes: 6 additions & 4 deletions django_jenkins/management/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ def __init__(self):
super(TaskListCommand, self).__init__()
self.tasks_cls = [import_module(module_name).Task for module_name in self.get_task_list()]

def handle(self, *test_labels, **options):
def initialize(self, *test_labels, **options):
# instantiate tasks
self.tasks = self.get_tasks(*test_labels, **options)

@@ -58,16 +58,18 @@ def handle(self, *test_labels, **options):
if signal_handler:
signal.connect(signal_handler)

# run
# setup test runner
test_runner_cls = get_runner()
test_runner = test_runner_cls(
self.test_runner = test_runner_cls(
output_dir=options['output_dir'],
interactive=options['interactive'],
debug=options['debug'],
verbosity=int(options.get('verbosity', 1)),
with_reports=options.get('with_reports', True))

if test_runner.run_tests(test_labels):
def handle(self, *test_labels, **options):
self.initialize(*test_labels, **options)
if self.test_runner.run_tests(test_labels):
sys.exit(1)

def get_tasks(self, *test_labels, **options):
52 changes: 52 additions & 0 deletions django_jenkins/management/commands/ci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# -*- coding: utf-8; mode: django -*-
import os
import sys
from itertools import groupby
from django.utils.importlib import import_module
from django_jenkins.standalone.storage import Storage
from django_jenkins.management.commands.jenkins import Command as BaseCICommand

def task_view(task):
return getattr(task, 'view', None)


class Command(BaseCICommand):
help = "Run CI process, and collect data for django_jenkins.standalon"
args = '[appname ...]'

def handle(self, *test_labels, **options):
storage = Storage.open()
build_id = storage['last_build_id'] + 1

# substitute output_dir
options['output_dir'] = os.path.join(Storage.ci_root(), 'build-%d' % build_id)

# run
self.initialize(*test_labels, **options)
result = self.test_runner.run_tests(test_labels)

# store results and exit
build_data = {}

# here is jenkins-task views come to play
build_data['views'] = []
self.tasks.sort(key=task_view)
for view_name, tasks in groupby(self.tasks, task_view):
view = import_module(view_name)
build_data[view_name] = view.get_build_data(tasks)
build_data['views'].append(view_name)

# tests
#test_result = self.test_runner.result
#build_data['tests-successes'] = len(test_result.successes)
#build_data['tests-failures'] = len(test_result.failures)
#build_data['tests-errors'] = len(test_result.errors)

# End jenkins-task views

storage['build-%d' % build_id] = build_data
storage['last_build_id'] = build_id
storage.close()

if result:
sys.exit(1)
Empty file.
38 changes: 38 additions & 0 deletions django_jenkins/standalone/storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# -*- coding: utf-8; mode: django -*-
import os
import shelve
from django.conf import settings


class Storage(object):
def __init__(self, storage):
self.storage = storage

@staticmethod
def ci_root():
ci_root = getattr(settings, 'CI_ROOT', os.path.join(settings.MEDIA_ROOT, 'ci'))
if not os.path.exists(ci_root):
os.makedirs(ci_root)
return ci_root

@staticmethod
def open():
storage = shelve.open(os.path.join(Storage.ci_root(), 'cidata.shelve'))
if 'version' not in storage:
storage['version'] = '1.0'
if 'last_build_id' not in storage:
storage['last_build_id'] = 0
return Storage(storage=storage)

def __getitem__(self, key):
return self.storage[key]

def __setitem__(self, key, value):
self.storage[key] = value

def __contains__(self, item):
return item in self.storage

def close(self):
self.storage.close()

39 changes: 39 additions & 0 deletions django_jenkins/standalone/taskviews/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8; mode: django -*-
"""
Store and view task results data in standalone ci
"""
from django.views.generic import View


class BaseTaskDataExtract(object):
def extract_build_data(self, tasks):
"""
Extrats current build ci data
"""
return {}

def extract_details_data(self, tasks):
"""
Extract details view data
"""
return None



class BaseTaskDataView(object):
"""
Renters html part of ci index page
"""
def add_build_data(self, build_id, build_data):
pass

def render_part(self, request):
pass


class TaskDetailView(View):
"""
Renders build task detail page
"""
def view(request, build_id, build_data):
pass
104 changes: 104 additions & 0 deletions django_jenkins/standalone/taskviews/tests_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# -*- coding: utf-8; mode: django -*-
"""
View for tasks with tests runner
"""
import math
import sys
from pygooglechart import Axis, SimpleLineChart
from django.template.loader import render_to_string
from django_jenkins.standalone import taskviews


class TaskDataExtract(taskviews.BaseTaskDataExtract):
"""
Extract data from test runner tasks.

Each task should have test_runner and output_file attributes
"""
def extract_build_data(self, tasks):
"""
Extrats current build ci data
"""
result = {}
result['tests-successes'] = 0
result['tests-failures'] = 0
result['tests-errors'] = 0

for task in tasks:
test_result = task.test_runner.result
result['tests-successes'] += len(test_result.successes)
result['tests-failures'] += len(test_result.failures)
result['tests-errors'] += len(test_result.errors)

return result

def extract_details_data(self, tasks):
"""
Extract details view data
"""
output = []
for task in tasks:
output.append(task.output_file)
return { 'output' : output }


class TaskDataView(taskviews.BaseTaskDataView):
"""
Renters html part of ci index page
"""
def __init__(self):
self.min_build_id, self.max_build_id = sys.max_int, 0
self.successes = []
self.failures = []
self.errors = []

def add_build_data(self, build_id, build_data):
self.min_build_id = min(build_id, self.min_build_id)
self.max_build_id = max(build_id, self.max_build_id)
self.successes.append(build_data['tests-successes'])
self.failures.append(build_data['tests-failures'])
self.errors.append(build_data['tests-errors'])

def build_chart(self):
tests_chart = SimpleLineChart(400, 250)
all_fails = [f+e for f,e in zip(self.failures, self.errors)]
all_results = [s+af for s,af in zip(self.successes, all_fails)]

# axis
max_tests = max(all_results)
step = round(max_tests/10, 1-len(str(max_tests/10)))
total_steps = math.ceil(1.0 * max_tests/step)
tests_chart.set_axis_labels(Axis.LEFT, xrange(0, step*(total_steps+1), step))
tests_chart.set_axis_labels(Axis.BOTTOM, xrange(self.min_build_id, self.max_build_id+1))
tests_chart.set_grid(0, step/2, 5, 5)

# First value - allowed maximum
tests_chart.add_data([step*total_steps] * 2)
# All tests, failures and errors, errors
tests_chart.add_data(all_results)
tests_chart.add_data(all_fails)
tests_chart.add_data(self.errors)
# Last value is the lowest in the Y axis.
tests_chart.add_data([0] * 2)

# Fill colors
tests_chart.set_colours(['FFFFFF', '00FF00', 'FF0000', '0000FF'])
tests_chart.add_fill_range('00FF00', 1, 2)
tests_chart.add_fill_range('FF0000', 2, 3)
tests_chart.add_fill_range('0000FF', 3, 4)

return tests_chart

def render_part(self, request):
return render_to_string('django_jenkins/tests_part.html',
{ 'chart' : self.build_chart(),
'title' : 'Tests result' })


class TaskDetailView(taskviews.BaseTaskDetailView):
"""
Renders build task detail page
"""
def view(request, build_id, build_data):
pass

8 changes: 8 additions & 0 deletions django_jenkins/standalone/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# -*- coding: utf-8; mode: django -*-
from django.conf.urls.defaults import patterns, url


urlpatterns = patterns('django_jenkins.standalone.views',
url(r'^$', 'index', name="ci_index"),
)

55 changes: 55 additions & 0 deletions django_jenkins/standalone/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8; mode: django -*-
import math
from pygooglechart import Axis, SimpleLineChart
from django.shortcuts import render
from django_jenkins.standalone.storage import Storage


def index(request):
try:
storage = Storage.open()

# TODO Here jenkins-task views come to play

# tests
last_build_id = storage['last_build_id']
successes, failures, errors = [], [], []
for build_id in xrange(1, last_build_id+1):
build_data = storage['build-%d' % build_id]
successes.append(build_data['tests-successes'])
failures.append(build_data['tests-failures'])
errors.append(build_data['tests-errors'])


tests_chart = SimpleLineChart(400, 250)
tests_chart.BASE_URL = 'http://chart.googleapis.com/chart?'
# axis
max_tests = max([s+f+e for s,f,e in zip(successes,failures,errors)])
step = round(max_tests/10, 1-len(str(max_tests/10)))
total_steps = math.ceil(1.0 * max_tests/step)
tests_chart.set_axis_labels(Axis.LEFT, xrange(0, step*(total_steps+1), step))
tests_chart.set_axis_labels(Axis.BOTTOM, xrange(1, last_build_id+1))
tests_chart.set_grid(0, step/2, 5, 5)

# First value - allowed maximum
tests_chart.add_data([step*total_steps] * 2)
# All tests, failures and errors, errors
tests_chart.add_data([s+f+e for s,f,e in zip(successes,failures,errors)])
tests_chart.add_data([f+e for f,e in zip(failures,errors)])
tests_chart.add_data(errors)
# Last value is the lowest in the Y axis.
tests_chart.add_data([0] * 2)

# Fill colors
tests_chart.set_colours(['FFFFFF', '00FF00', 'FF0000', '0000FF'])
tests_chart.add_fill_range('00FF00', 1, 2)
tests_chart.add_fill_range('FF0000', 2, 3)
tests_chart.add_fill_range('0000FF', 3, 4)

# End jenkins-task views

return render(request, 'django_jenkins/index.html',
{ 'tests_chart' : tests_chart })
finally:
storage.close()

1 change: 1 addition & 0 deletions django_jenkins/tasks/__init__.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ class BaseTask(object):
"""
Base interface for ci tasks
"""
view = None
option_list = []

def __init__(self, test_labels, options):
2 changes: 1 addition & 1 deletion django_jenkins/tasks/csslint
2 changes: 2 additions & 0 deletions django_jenkins/tasks/dir_tests.py
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ def build_suite(app):


class Task(BaseTask):
view = 'django_jenkins.standalone.taskviews.tests_view'

def __init__(self, test_labels, options):
super(Task, self).__init__(test_labels, options)
if not self.test_labels:
2 changes: 2 additions & 0 deletions django_jenkins/tasks/django_tests.py
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@


class Task(BaseTask):
view = 'django_jenkins.standalone.taskviews.tests_view'

def __init__(self, test_labels, options):
super(Task, self).__init__(test_labels, options)
if not self.test_labels:
2 changes: 1 addition & 1 deletion django_jenkins/tasks/jslint
2 changes: 2 additions & 0 deletions django_jenkins/tasks/lettuce_tests.py
Original file line number Diff line number Diff line change
@@ -10,6 +10,8 @@


class Task(BaseTask):
view = 'django_jenkins.standalone.taskviews.tests_view'

option_list = [
make_option("--lettuce-server",
dest="lettuce-server",
10 changes: 10 additions & 0 deletions django_jenkins/templates/django_jenkins/base_ci.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html>
<head>
<title>Continous integration results</title>
</head>
<body>
<h1>CI results</h1>
{% block content %}
{% endblock %}
</body>
</html>
5 changes: 5 additions & 0 deletions django_jenkins/templates/django_jenkins/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends 'django_jenkins/base_ci.html' %}

{% block content %}
<img src="{{ tests_chart.get_url }}">
{% endblock %}'
Loading