crazy_ivan 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/crazy_ivan.gemspec +17 -8
- data/lib/{report_assembler.rb → crazy_ivan/report_assembler.rb} +16 -9
- data/lib/crazy_ivan.rb +4 -3
- data/templates/css/ci.css +22 -5
- data/templates/index.html +68 -55
- data/templates/javascript/builder.js +136 -0
- data/templates/javascript/controls.js +965 -0
- data/templates/javascript/date.js +145 -0
- data/templates/javascript/dragdrop.js +974 -0
- data/templates/javascript/effects.js +1123 -0
- data/templates/javascript/scriptaculous.js +68 -0
- data/templates/javascript/slider.js +275 -0
- data/test/crazy_ivan_test.rb +4 -0
- metadata +13 -5
- /data/lib/{html_asset_crush.rb → crazy_ivan/html_asset_crush.rb} +0 -0
- /data/lib/{test_runner.rb → crazy_ivan/test_runner.rb} +0 -0
data/Rakefile
CHANGED
@@ -20,9 +20,9 @@ begin
|
|
20
20
|
gem.rubyforge_project = "crazyivan"
|
21
21
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
22
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
|
24
|
+
Jeweler::GemcutterTasks.new
|
25
|
+
|
26
26
|
rescue LoadError
|
27
27
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
28
28
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/crazy_ivan.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{crazy_ivan}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Edward Ocampo-Gooding"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-11-29}
|
13
13
|
s.default_executable = %q{crazy_ivan}
|
14
14
|
s.description = %q{Continuous integration should really just be a script that captures the output of running your project update & test commands and presents recent results in a static html page.
|
15
15
|
|
@@ -23,7 +23,8 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.executables = ["crazy_ivan"]
|
24
24
|
s.extra_rdoc_files = [
|
25
25
|
"LICENSE",
|
26
|
-
"README.rdoc"
|
26
|
+
"README.rdoc",
|
27
|
+
"TODO"
|
27
28
|
]
|
28
29
|
s.files = [
|
29
30
|
".gitignore",
|
@@ -35,13 +36,20 @@ Gem::Specification.new do |s|
|
|
35
36
|
"bin/crazy_ivan",
|
36
37
|
"crazy_ivan.gemspec",
|
37
38
|
"lib/crazy_ivan.rb",
|
38
|
-
"lib/html_asset_crush.rb",
|
39
|
-
"lib/report_assembler.rb",
|
40
|
-
"lib/test_runner.rb",
|
39
|
+
"lib/crazy_ivan/html_asset_crush.rb",
|
40
|
+
"lib/crazy_ivan/report_assembler.rb",
|
41
|
+
"lib/crazy_ivan/test_runner.rb",
|
41
42
|
"templates/css/ci.css",
|
42
43
|
"templates/index.html",
|
44
|
+
"templates/javascript/builder.js",
|
45
|
+
"templates/javascript/controls.js",
|
46
|
+
"templates/javascript/date.js",
|
47
|
+
"templates/javascript/dragdrop.js",
|
48
|
+
"templates/javascript/effects.js",
|
43
49
|
"templates/javascript/json-template.js",
|
44
50
|
"templates/javascript/prototype.js",
|
51
|
+
"templates/javascript/scriptaculous.js",
|
52
|
+
"templates/javascript/slider.js",
|
45
53
|
"test/crazy_ivan_test.rb",
|
46
54
|
"test/test_helper.rb",
|
47
55
|
"vendor/json-1.1.7/CHANGES",
|
@@ -180,3 +188,4 @@ Gem::Specification.new do |s|
|
|
180
188
|
else
|
181
189
|
end
|
182
190
|
end
|
191
|
+
|
@@ -21,14 +21,21 @@ class ReportAssembler
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
string[0..240]
|
24
|
+
def filename_from_version(string)
|
25
|
+
s = string[0..240]
|
26
|
+
|
27
|
+
if Dir["#{s}*.json"].size > 0
|
28
|
+
s += "-#{Dir["#{s}*.json"].size}"
|
29
|
+
end
|
30
|
+
|
31
|
+
s
|
26
32
|
end
|
27
33
|
|
28
34
|
def update_project(result)
|
29
35
|
FileUtils.mkdir_p(result.project_name)
|
30
36
|
Dir.chdir(result.project_name) do
|
31
|
-
|
37
|
+
filename = filename_from_version(result.version_output)
|
38
|
+
File.open("#{filename}.json", 'w+') do |f|
|
32
39
|
f.puts({
|
33
40
|
"version" => result.version_output,
|
34
41
|
"timestamp" => result.timestamp,
|
@@ -39,11 +46,11 @@ class ReportAssembler
|
|
39
46
|
}.to_json)
|
40
47
|
end
|
41
48
|
|
42
|
-
update_recent(result)
|
49
|
+
update_recent(result, filename)
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
46
|
-
def update_recent(result)
|
53
|
+
def update_recent(result, filename)
|
47
54
|
recent_versions_json = File.open('recent.json', File::RDWR|File::CREAT).read
|
48
55
|
|
49
56
|
recent_versions = []
|
@@ -52,19 +59,19 @@ class ReportAssembler
|
|
52
59
|
recent_versions = JSON.parse(recent_versions_json)["recent_versions"]
|
53
60
|
end
|
54
61
|
|
55
|
-
recent_versions <<
|
62
|
+
recent_versions << filename
|
56
63
|
recent_versions.shift if recent_versions.size > MAXIMUM_RECENTS
|
57
64
|
|
58
65
|
File.open('recent.json', 'w+') do |f|
|
59
|
-
f.print
|
66
|
+
f.print({"recent_versions" => recent_versions}.to_json)
|
60
67
|
end
|
61
68
|
end
|
62
69
|
|
63
70
|
def update_projects
|
64
|
-
projects = @test_results.map {|r| "
|
71
|
+
projects = @test_results.map {|r| "#{r.project_name}"}
|
65
72
|
|
66
73
|
File.open('projects.json', 'w+') do |f|
|
67
|
-
f.print
|
74
|
+
f.print({"projects" => projects}.to_json)
|
68
75
|
end
|
69
76
|
end
|
70
77
|
|
data/lib/crazy_ivan.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'yaml'
|
3
|
-
|
4
|
-
require
|
5
|
-
require
|
3
|
+
|
4
|
+
require 'crazy_ivan/report_assembler'
|
5
|
+
require 'crazy_ivan/test_runner'
|
6
|
+
require 'crazy_ivan/html_asset_crush'
|
data/templates/css/ci.css
CHANGED
@@ -3,14 +3,31 @@ body {
|
|
3
3
|
padding: 0;
|
4
4
|
background: #fff;
|
5
5
|
color: #333;
|
6
|
-
font: 100%/1.5
|
6
|
+
font: 100%/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
|
7
7
|
}
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
}
|
9
|
+
h1 { margin: 0;}
|
10
|
+
|
11
|
+
pre { margin: 0;}
|
13
12
|
|
14
13
|
.error {
|
15
14
|
color: red;
|
15
|
+
}
|
16
|
+
|
17
|
+
.project h2 { margin: 12px 0 0 0;}
|
18
|
+
|
19
|
+
.tests { margin: 0 0 0 18px;}
|
20
|
+
.tests .test { font-size: 80%; margin-right: 8px;}
|
21
|
+
.tests .latest { font-size: 100%;}
|
22
|
+
|
23
|
+
.results .result { margin: 12px 18px 8px 18px;}
|
24
|
+
.results .result .timestamp { margin-right: 12px;}
|
25
|
+
.results .result .update { margin: 6px 0 6px 12px }
|
26
|
+
.results .result .test { margin: 6px 0 6px 12px }
|
27
|
+
|
28
|
+
.footer {
|
29
|
+
margin: 24px 0 0 0;
|
30
|
+
font-size: 60%;
|
31
|
+
width: 100%;
|
32
|
+
text-align: center;
|
16
33
|
}
|
data/templates/index.html
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
|
8
8
|
<link rel="stylesheet" href="css/ci.css" type="text/css" charset="utf-8">
|
9
9
|
<script type="text/javascript" src="javascript/prototype.js"></script>
|
10
|
+
<script type="text/javascript" src="javascript/scriptaculous.js"></script>
|
11
|
+
<script type="text/javascript" src="javascript/date.js"></script>
|
10
12
|
<script type="text/javascript" src="javascript/json-template.js"></script>
|
11
13
|
<script type="text/javascript">
|
12
14
|
var init = function() {
|
@@ -68,72 +70,83 @@
|
|
68
70
|
}
|
69
71
|
|
70
72
|
var render = function(template_name, json) {
|
71
|
-
var template = jsontemplate.Template("
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
<
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
<
|
89
|
-
<
|
90
|
-
|
91
|
-
<
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
73
|
+
var template = jsontemplate.Template(" \
|
74
|
+
<h1>Projects</h1> \
|
75
|
+
<div class='projects'> \
|
76
|
+
{.section projects} \
|
77
|
+
{.repeated section @} \
|
78
|
+
<div class='project'> \
|
79
|
+
<h2>{name}</h2> \
|
80
|
+
<div class='tests'> \
|
81
|
+
{.section reports} \
|
82
|
+
{.repeated section @} \
|
83
|
+
<a class='test {.section test_error} error {.end} {.section update_error} error {.end}' href='#'>{timestamp}</a> \
|
84
|
+
{.end} \
|
85
|
+
{.end} \
|
86
|
+
</div> \
|
87
|
+
<div class='results'> \
|
88
|
+
{.section reports} \
|
89
|
+
{.repeated section @} \
|
90
|
+
<div class='result'> \
|
91
|
+
<div> \
|
92
|
+
<span class='timestamp'>{timestamp}</span> \
|
93
|
+
<span class='version'>{version}</span> \
|
94
|
+
</div> \
|
95
|
+
\
|
96
|
+
<div class='update'> \
|
97
|
+
<pre>{update}</pre> \
|
98
|
+
{.section update_error} \
|
99
|
+
<pre class='error'>{update_error}</pre> \
|
100
|
+
{.end} \
|
101
|
+
</div> \
|
102
|
+
\
|
103
|
+
<div class='test'> \
|
104
|
+
<pre>{test}</pre> \
|
105
|
+
{.section test_error} \
|
106
|
+
<pre class='error'>{test_error}</pre> \
|
107
|
+
{.end} \
|
108
|
+
</div> \
|
109
|
+
</div> \
|
110
|
+
{.end} \
|
111
|
+
{.or} \
|
112
|
+
<p>No test reports found. Please run the `ci` executable.</p> \
|
113
|
+
{.end} \
|
114
|
+
</div> \
|
115
|
+
</div> \
|
116
|
+
{.end} \
|
117
|
+
{.or} \
|
118
|
+
<p>No projects found.</p> \
|
119
|
+
{.end} \
|
120
|
+
</div> \
|
114
121
|
");
|
115
122
|
|
116
123
|
var html = template.expand(json);
|
117
124
|
$("replace").update(html);
|
118
125
|
|
119
|
-
// Hide all errors by default
|
120
|
-
$$('.error').invoke('hide');
|
121
126
|
|
122
|
-
$$('.project').each(function(
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
$$('.project .tests').each(function(t) {
|
128
|
+
t.down('.test').addClassName('latest')
|
129
|
+
});
|
130
|
+
|
131
|
+
// Reformat the test timestamps to be less enormous
|
132
|
+
$$('.project .tests .test').each(function(t) {
|
133
|
+
t.update(Date.parse(t.innerHTML).toString("HH:mm"));
|
134
|
+
t.observe('click', function(e) {
|
135
|
+
console.debug("hallo");
|
136
|
+
$$('.results').invoke('show')
|
137
|
+
return false;
|
138
|
+
});
|
132
139
|
});
|
140
|
+
|
141
|
+
$$('.results').invoke('hide')
|
133
142
|
}
|
134
143
|
</script>
|
135
144
|
</head>
|
136
145
|
<body onload="init();">
|
137
146
|
<div id="replace"></div>
|
147
|
+
|
148
|
+
<div class="footer">
|
149
|
+
<a href="http://github.com/edward/crazy_ivan">Crazy Ivan on Github</a>
|
150
|
+
</div>
|
138
151
|
</body>
|
139
152
|
</html>
|
@@ -0,0 +1,136 @@
|
|
1
|
+
// script.aculo.us builder.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
|
2
|
+
|
3
|
+
// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
4
|
+
//
|
5
|
+
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
6
|
+
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
7
|
+
|
8
|
+
var Builder = {
|
9
|
+
NODEMAP: {
|
10
|
+
AREA: 'map',
|
11
|
+
CAPTION: 'table',
|
12
|
+
COL: 'table',
|
13
|
+
COLGROUP: 'table',
|
14
|
+
LEGEND: 'fieldset',
|
15
|
+
OPTGROUP: 'select',
|
16
|
+
OPTION: 'select',
|
17
|
+
PARAM: 'object',
|
18
|
+
TBODY: 'table',
|
19
|
+
TD: 'table',
|
20
|
+
TFOOT: 'table',
|
21
|
+
TH: 'table',
|
22
|
+
THEAD: 'table',
|
23
|
+
TR: 'table'
|
24
|
+
},
|
25
|
+
// note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
|
26
|
+
// due to a Firefox bug
|
27
|
+
node: function(elementName) {
|
28
|
+
elementName = elementName.toUpperCase();
|
29
|
+
|
30
|
+
// try innerHTML approach
|
31
|
+
var parentTag = this.NODEMAP[elementName] || 'div';
|
32
|
+
var parentElement = document.createElement(parentTag);
|
33
|
+
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
|
34
|
+
parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
|
35
|
+
} catch(e) {}
|
36
|
+
var element = parentElement.firstChild || null;
|
37
|
+
|
38
|
+
// see if browser added wrapping tags
|
39
|
+
if(element && (element.tagName.toUpperCase() != elementName))
|
40
|
+
element = element.getElementsByTagName(elementName)[0];
|
41
|
+
|
42
|
+
// fallback to createElement approach
|
43
|
+
if(!element) element = document.createElement(elementName);
|
44
|
+
|
45
|
+
// abort if nothing could be created
|
46
|
+
if(!element) return;
|
47
|
+
|
48
|
+
// attributes (or text)
|
49
|
+
if(arguments[1])
|
50
|
+
if(this._isStringOrNumber(arguments[1]) ||
|
51
|
+
(arguments[1] instanceof Array) ||
|
52
|
+
arguments[1].tagName) {
|
53
|
+
this._children(element, arguments[1]);
|
54
|
+
} else {
|
55
|
+
var attrs = this._attributes(arguments[1]);
|
56
|
+
if(attrs.length) {
|
57
|
+
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
|
58
|
+
parentElement.innerHTML = "<" +elementName + " " +
|
59
|
+
attrs + "></" + elementName + ">";
|
60
|
+
} catch(e) {}
|
61
|
+
element = parentElement.firstChild || null;
|
62
|
+
// workaround firefox 1.0.X bug
|
63
|
+
if(!element) {
|
64
|
+
element = document.createElement(elementName);
|
65
|
+
for(attr in arguments[1])
|
66
|
+
element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
|
67
|
+
}
|
68
|
+
if(element.tagName.toUpperCase() != elementName)
|
69
|
+
element = parentElement.getElementsByTagName(elementName)[0];
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
// text, or array of children
|
74
|
+
if(arguments[2])
|
75
|
+
this._children(element, arguments[2]);
|
76
|
+
|
77
|
+
return $(element);
|
78
|
+
},
|
79
|
+
_text: function(text) {
|
80
|
+
return document.createTextNode(text);
|
81
|
+
},
|
82
|
+
|
83
|
+
ATTR_MAP: {
|
84
|
+
'className': 'class',
|
85
|
+
'htmlFor': 'for'
|
86
|
+
},
|
87
|
+
|
88
|
+
_attributes: function(attributes) {
|
89
|
+
var attrs = [];
|
90
|
+
for(attribute in attributes)
|
91
|
+
attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
|
92
|
+
'="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"');
|
93
|
+
return attrs.join(" ");
|
94
|
+
},
|
95
|
+
_children: function(element, children) {
|
96
|
+
if(children.tagName) {
|
97
|
+
element.appendChild(children);
|
98
|
+
return;
|
99
|
+
}
|
100
|
+
if(typeof children=='object') { // array can hold nodes and text
|
101
|
+
children.flatten().each( function(e) {
|
102
|
+
if(typeof e=='object')
|
103
|
+
element.appendChild(e);
|
104
|
+
else
|
105
|
+
if(Builder._isStringOrNumber(e))
|
106
|
+
element.appendChild(Builder._text(e));
|
107
|
+
});
|
108
|
+
} else
|
109
|
+
if(Builder._isStringOrNumber(children))
|
110
|
+
element.appendChild(Builder._text(children));
|
111
|
+
},
|
112
|
+
_isStringOrNumber: function(param) {
|
113
|
+
return(typeof param=='string' || typeof param=='number');
|
114
|
+
},
|
115
|
+
build: function(html) {
|
116
|
+
var element = this.node('div');
|
117
|
+
$(element).update(html.strip());
|
118
|
+
return element.down();
|
119
|
+
},
|
120
|
+
dump: function(scope) {
|
121
|
+
if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
|
122
|
+
|
123
|
+
var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
|
124
|
+
"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
|
125
|
+
"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
|
126
|
+
"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
|
127
|
+
"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
|
128
|
+
"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
|
129
|
+
|
130
|
+
tags.each( function(tag){
|
131
|
+
scope[tag] = function() {
|
132
|
+
return Builder.node.apply(Builder, [tag].concat($A(arguments)));
|
133
|
+
};
|
134
|
+
});
|
135
|
+
}
|
136
|
+
};
|