Skip to content

Commit d04149e

Browse files
committed
merged master back in
2 parents da80503 + 5ef6809 commit d04149e

18 files changed

Lines changed: 517 additions & 289 deletions

codespeed/git.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,12 @@
1010

1111

1212
def updaterepo(project, update=True):
13-
repo_name = os.path.splitext(project.repo_path.split(os.sep)[-1])[0]
14-
working_copy = os.path.join(settings.REPOSITORY_BASE_PATH, repo_name)
15-
16-
if os.path.exists(working_copy):
13+
if os.path.exists(project.working_copy):
1714
if not update:
1815
return
1916

2017
p = Popen(['git', 'pull'], stdout=PIPE, stderr=PIPE,
21-
cwd=working_copy)
18+
cwd=project.working_copy)
2219

2320
stdout, stderr = p.communicate()
2421
if p.returncode != 0:
@@ -27,7 +24,7 @@ def updaterepo(project, update=True):
2724
else:
2825
return [{'error': False}]
2926
else:
30-
cmd = ['git', 'clone', project.repo_path, repo_name]
27+
cmd = ['git', 'clone', project.repo_path, project.repo_name]
3128
p = Popen(cmd, stdout=PIPE, stderr=PIPE,
3229
cwd=settings.REPOSITORY_BASE_PATH)
3330
logger.debug('Cloning Git repo {0} for project {1}'.format(
@@ -43,11 +40,6 @@ def updaterepo(project, update=True):
4340
def getlogs(endrev, startrev):
4441
updaterepo(endrev.branch.project, update=False)
4542

46-
# TODO: Move all of this onto the model so we can avoid needing to repeat it:
47-
repo_name = os.path.splitext(
48-
endrev.branch.project.repo_path.split(os.sep)[-1])[0]
49-
working_copy = os.path.join(settings.REPOSITORY_BASE_PATH, repo_name)
50-
5143
cmd = ["git", "log",
5244
# NULL separated values delimited by 0x1e record separators
5345
# See PRETTY FORMATS in git-log(1):
@@ -59,6 +51,7 @@ def getlogs(endrev, startrev):
5951
cmd.append("-1") # Only return one commit
6052
cmd.append(endrev.commitid)
6153

54+
working_copy = endrev.branch.project.working_copy
6255
p = Popen(cmd, stdout=PIPE, stderr=PIPE, cwd=working_copy)
6356

6457
stdout, stderr = p.communicate()

codespeed/github.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ def retrieve_revision(commit_id, username, project, revision = None):
7878
'author_email': commit['author']['email'],
7979
'commitid': commit['id'],
8080
'short_commit_id': commit['id'][0:7],
81-
'links': {'Github': 'http://github.com%s' % commit['url']},
8281
'parents': commit['parents']}
8382

8483
def getlogs(endrev, startrev):

codespeed/mercurial.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@
99

1010

1111
def updaterepo(project, update=True):
12-
repo_name = os.path.splitext(project.repo_path.split(os.sep)[-1])[0]
13-
working_copy = os.path.join(settings.REPOSITORY_BASE_PATH, repo_name)
14-
15-
if os.path.exists(working_copy):
12+
if os.path.exists(project.working_copy):
1613
if not update:
1714
return
1815

1916
p = Popen(['hg', 'pull', '-u'], stdout=PIPE, stderr=PIPE,
20-
cwd=working_copy)
17+
cwd=project.working_copy)
2118
stdout, stderr = p.communicate()
2219

2320
if p.returncode != 0 or stderr:
@@ -27,7 +24,7 @@ def updaterepo(project, update=True):
2724
return [{'error': False}]
2825
else:
2926
# Clone repo
30-
cmd = ['hg', 'clone', project.repo_path, repo_name]
27+
cmd = ['hg', 'clone', project.repo_path, project.repo_name]
3128

3229
p = Popen(cmd, stdout=PIPE, stderr=PIPE,
3330
cwd=settings.REPOSITORY_BASE_PATH)
@@ -45,15 +42,12 @@ def updaterepo(project, update=True):
4542
def getlogs(endrev, startrev):
4643
updaterepo(endrev.branch.project, update=False)
4744

48-
# TODO: Move all of this onto the model so we can avoid needing to repeat it:
49-
repo_name = os.path.splitext(endrev.branch.project.repo_path.split(os.sep)[-1])[0]
50-
working_copy = os.path.join(settings.REPOSITORY_BASE_PATH, repo_name)
51-
5245
cmd = ["hg", "log",
5346
"-r", "%s:%s" % (endrev.commitid, startrev.commitid),
5447
"-b", "default",
5548
"--template", "{rev}:{node|short}\n{node}\n{author|user}\n{author|email}\n{date}\n{desc}\n=newlog=\n"]
5649

50+
working_copy = endrev.branch.project.working_copy
5751
p = Popen(cmd, stdout=PIPE, stderr=PIPE, cwd=working_copy)
5852
stdout, stderr = p.communicate()
5953

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# encoding: utf-8
2+
import datetime
3+
from south.db import db
4+
from south.v2 import SchemaMigration
5+
from django.db import models
6+
7+
class Migration(SchemaMigration):
8+
9+
def forwards(self, orm):
10+
11+
# Adding field 'Project.commit_browsing_url'
12+
db.add_column('codespeed_project', 'commit_browsing_url', self.gf('django.db.models.fields.CharField')(default='', max_length=200, blank=True), keep_default=False)
13+
14+
15+
def backwards(self, orm):
16+
17+
# Deleting field 'Project.commit_browsing_url'
18+
db.delete_column('codespeed_project', 'commit_browsing_url')
19+
20+
21+
models = {
22+
'codespeed.benchmark': {
23+
'Meta': {'object_name': 'Benchmark'},
24+
'benchmark_type': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '1'}),
25+
'default_on_comparison': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
26+
'description': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
27+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
28+
'lessisbetter': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
29+
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
30+
'units': ('django.db.models.fields.CharField', [], {'default': "'seconds'", 'max_length': '20'}),
31+
'units_title': ('django.db.models.fields.CharField', [], {'default': "'Time'", 'max_length': '30'})
32+
},
33+
'codespeed.branch': {
34+
'Meta': {'unique_together': "(('name', 'project'),)", 'object_name': 'Branch'},
35+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
36+
'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
37+
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'branches'", 'to': "orm['codespeed.Project']"})
38+
},
39+
'codespeed.environment': {
40+
'Meta': {'object_name': 'Environment'},
41+
'cpu': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
42+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
43+
'kernel': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
44+
'memory': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
45+
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
46+
'os': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'})
47+
},
48+
'codespeed.executable': {
49+
'Meta': {'object_name': 'Executable'},
50+
'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
51+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
52+
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
53+
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'executables'", 'to': "orm['codespeed.Project']"})
54+
},
55+
'codespeed.project': {
56+
'Meta': {'object_name': 'Project'},
57+
'commit_browsing_url': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
58+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
59+
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
60+
'repo_pass': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
61+
'repo_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
62+
'repo_type': ('django.db.models.fields.CharField', [], {'default': "'N'", 'max_length': '1'}),
63+
'repo_user': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
64+
'track': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
65+
},
66+
'codespeed.report': {
67+
'Meta': {'unique_together': "(('revision', 'executable', 'environment'),)", 'object_name': 'Report'},
68+
'_tablecache': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
69+
'colorcode': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '10'}),
70+
'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Environment']"}),
71+
'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Executable']"}),
72+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73+
'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Revision']"}),
74+
'summary': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'})
75+
},
76+
'codespeed.result': {
77+
'Meta': {'unique_together': "(('revision', 'executable', 'benchmark', 'environment'),)", 'object_name': 'Result'},
78+
'benchmark': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Benchmark']"}),
79+
'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
80+
'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Environment']"}),
81+
'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Executable']"}),
82+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
83+
'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Revision']"}),
84+
'std_dev': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
85+
'val_max': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
86+
'val_min': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
87+
'value': ('django.db.models.fields.FloatField', [], {})
88+
},
89+
'codespeed.revision': {
90+
'Meta': {'unique_together': "(('commitid', 'branch'),)", 'object_name': 'Revision'},
91+
'author': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
92+
'branch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['codespeed.Branch']"}),
93+
'commitid': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
94+
'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
95+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
96+
'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
97+
'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['codespeed.Project']"}),
98+
'tag': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'})
99+
}
100+
}
101+
102+
complete_apps = ['codespeed']

codespeed/models.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# -*- coding: utf-8 -*-
2+
import os
3+
24
from django.core.exceptions import ValidationError
35
from django.core.urlresolvers import reverse
46
from django.db import models
57
from django.utils import simplejson as json
68

79
from django.conf import settings
810

11+
from codespeed.github import GITHUB_URL_RE
12+
913

1014
class Project(models.Model):
1115
REPO_TYPES = (
@@ -22,11 +26,42 @@ class Project(models.Model):
2226
repo_path = models.CharField("Repository URL", blank=True, max_length=200)
2327
repo_user = models.CharField("Repository username", blank=True, max_length=100)
2428
repo_pass = models.CharField("Repository password", blank=True, max_length=100)
29+
commit_browsing_url = models.CharField("Commit browsing URL", blank=True, max_length=200)
2530
track = models.BooleanField("Track changes", default=False)
2631

2732
def __unicode__(self):
2833
return self.name
2934

35+
@property
36+
def repo_name(self):
37+
# name not defined for None, GitHub or Subversion
38+
if self.repo_type in ('N', 'H', 'S'):
39+
error = 'Not supported for %s project' % self.get_repo_type_display()
40+
raise AttributeError(error)
41+
42+
return os.path.splitext(self.repo_path.split(os.sep)[-1])[0]
43+
44+
@property
45+
def working_copy(self):
46+
# working copy exists for mercurial and git only
47+
if self.repo_type in ('N', 'H', 'S'):
48+
error = 'Not supported for %s project' % self.get_repo_type_display()
49+
raise AttributeError(error)
50+
51+
return os.path.join(settings.REPOSITORY_BASE_PATH, self.repo_name)
52+
53+
def save(self, *args, **kwargs):
54+
"""Provide a default for commit browsing url in github repositories."""
55+
if not self.commit_browsing_url and self.repo_type == 'H':
56+
m = GITHUB_URL_RE.match(self.repo_path)
57+
if m:
58+
url = 'https://github.com/%s/%s/commit/{commitid}' % (
59+
m.group('username'), m.group('project')
60+
)
61+
self.commit_browsing_url = url
62+
63+
super(Project, self).save(*args, **kwargs)
64+
3065

3166
class Branch(models.Model):
3267
name = models.CharField(max_length=20)
@@ -53,6 +88,9 @@ class Revision(models.Model):
5388
def get_short_commitid(self):
5489
return self.commitid[:10]
5590

91+
def get_browsing_url(self):
92+
return self.branch.project.commit_browsing_url.format(**self.__dict__)
93+
5694
def __unicode__(self):
5795
if self.date is None:
5896
date = None

codespeed/static/js/changes.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
var Changes = (function(window){
2+
3+
// Localize globals
4+
var TIMELINE_URL = window.TIMELINE_URL, getLoadText = window.getLoadText;
5+
16
var currentproject, changethres, trendthres, projectmatrix, revisionboxes = {};
27

38
function getConfiguration() {
@@ -122,4 +127,17 @@ function init(defaults) {
122127
$("#revision").html(revisionboxes[defaults.project]);
123128
$("#revision").val(defaults.revision);
124129
$("#revision").change(refreshContent);
130+
131+
$("#permalink").click(function() {
132+
window.location = "?" + $.param(getConfiguration());
133+
});
134+
135+
refreshContent();
125136
}
137+
138+
return {
139+
init: init,
140+
config: config
141+
};
142+
143+
})(window);

codespeed/static/js/codespeed.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
2-
function permalink() {
3-
window.location="?" + $.param(getConfiguration());
4-
}
5-
61
function readCheckbox(el) {
72
/* Builds a string that holds all checked values in an input form */
83
var config = "";
@@ -30,3 +25,22 @@ function getLoadText(text, h, showloader) {
3025
loadtext += '</p></div>';
3126
return loadtext;
3227
}
28+
29+
$(function() {
30+
// Check all and none links
31+
$('.checkall').each(function() {
32+
var inputs = $(this).parent().children("li").children("input");
33+
$(this).click(function() {
34+
inputs.attr("checked", true);
35+
return false;
36+
});
37+
});
38+
39+
$('.uncheckall').each(function() {
40+
var inputs = $(this).parent().children("li").children("input");
41+
$(this).click(function() {
42+
inputs.attr("checked", false);
43+
return false;
44+
});
45+
});
46+
});

codespeed/static/js/comparison.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
var Comparison = (function(window){
2+
3+
// Localize globals
4+
var readCheckbox = window.readCheckbox, getLoadText = window.getLoadText;
5+
6+
var compdata, bench_units;
7+
18
function getConfiguration() {
29
return {
310
exe: readCheckbox("input[name='executables']:checked"),
@@ -375,3 +382,51 @@ function renderComparisonPlot(plotid, benchmarks, exes, enviros, baseline, chart
375382
$("#" + plotid).css('height', h);
376383
$.jqplot(plotid, plotdata, plotoptions);
377384
}
385+
386+
function init(defaults) {
387+
bench_units = defaults.bench_units;
388+
389+
// Set default values
390+
$("#chart_type").val(defaults.chart_type);
391+
$("#baseline").val(defaults.baseline);
392+
$("#direction").attr("checked", defaults.direction === "True");
393+
394+
var sel = $("input[name='executables']");
395+
$.each(defaults.executables, function(i, exe) {
396+
sel.filter("[value='" + exe + "']").attr('checked', true);
397+
});
398+
399+
sel = $("input[name='benchmarks']");
400+
$.each(defaults.benchmarks, function(i, bench) {
401+
sel.filter("[value='" + bench + "']").attr('checked', true);
402+
});
403+
404+
sel = $("input[name='environments']");
405+
$.each(defaults.environments, function(i, env) {
406+
sel.filter("[value='" + env + "']").attr('checked', true);
407+
});
408+
409+
$("#chart_type, #baseline, #direction, input[name='executables']," +
410+
"input[name='benchmarks'], input[name='environments']").change(refreshContent);
411+
412+
$('.checkall, .uncheckall').click(refreshContent);
413+
414+
$.ajaxSetup ({
415+
cache: false
416+
});
417+
418+
// Get comparison data
419+
var h = $("#content").height();//get height for loading text
420+
$("#cplot").html(getLoadText("Loading...", h, true));
421+
$.getJSON("json/", savedata);
422+
423+
$("#permalink").click(function() {
424+
window.location = "?" + $.param(getConfiguration());
425+
});
426+
}
427+
428+
return {
429+
init: init
430+
};
431+
432+
})(window);

0 commit comments

Comments
 (0)