buildboard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ builds
23
+ buildboard.gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jacob Atzen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ # buildboard
2
+
3
+ buildboard is an [Integrity][1] style dashboard meant to be used in
4
+ combination with [CI Joe][2]. It does not provide any build features only
5
+ aggregation of the output from a continuous integration system like CI Joe.
6
+
7
+ [1]: http://www.integrityapp.com
8
+ [2]: http://github.com/defunkt/cijoe
9
+
10
+ ## Getting started
11
+
12
+ To get started run:
13
+
14
+ gem install buildboard
15
+ buildboard
16
+
17
+ This will provide you with a running buildboard instance on port 5678 if
18
+ nothing else is already running on that port.
19
+
20
+ ## Setting up CI Joe
21
+
22
+ To start collecting data from CI Joe setup a `build-failed` and a
23
+ `build-worked` hook with the following content:
24
+
25
+ #!/bin/sh
26
+ update-buildboard --directory [path to your CI Joe working repository]
27
+
28
+ See the CI Joe documentation if you're in doubt about this.
29
+
30
+ The options for update-buildboard are:
31
+
32
+ Usage: update-buildboard [-hpd]
33
+
34
+ Specific options:
35
+ -h, --host=HOST The hostname or ip of the host running buildboard (default 127.0.0.1)
36
+ -p, --port=PORT The port buildboard is running on (default 5678)
37
+ -d, --directory=DIRECTORY The directory containing the CI Joe repository
38
+
39
+ ## Inner workings
40
+
41
+ You don't need to know this if you don't care.
42
+
43
+ All build information are stored in files in $HOME/.buildboard, they're just
44
+ YAML files, go peek if you want.
45
+
46
+ The protocol for integrating with buildboard can be derived from Build#load\_file.
47
+
48
+ ## Acknowledgements
49
+
50
+ buildboard is based on and/or stole from, and would like to thank:
51
+
52
+ * [Integrity][1] provided a nice design to steal
53
+ * [CI Joe][2] is the reason buildboard was made
54
+ * [Sinatra][3] is the muse that underlies it all
55
+ * [Vegas][4] for making it crazy easy to provide a stage for Sinatra
56
+
57
+ [3]: http://www.sinatrarb.com/
58
+ [4]: http://code.quirkey.com/vegas/
59
+
60
+ ## Note on Patches/Pull Requests
61
+
62
+ * Fork the project.
63
+ * Make your feature addition or bug fix.
64
+ * Add tests for it. This is important so I don't break it in a
65
+ future version unintentionally.
66
+ * Commit, do not mess with rakefile, version, or history.
67
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
68
+ * Send me a pull request. Bonus points for topic branches.
69
+
70
+ ## Copyright
71
+
72
+ Copyright (c) 2010 Jacob Atzen. See LICENSE for details.
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "buildboard"
8
+ gem.summary = %Q{Integrity style dashboard for CI Joe}
9
+ gem.description = %Q{Buildboard is an Integrity style dashboard for CI Joe}
10
+ gem.email = "jacob@incremental.dk"
11
+ gem.homepage = "http://github.com/jacobat/buildboard"
12
+ gem.authors = ["Jacob Atzen"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "buildboard #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'vegas'
5
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/buildboard.rb')
6
+
7
+ Vegas::Runner.new(Buildboard, 'buildboard')
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'uri'
5
+ require 'fileutils'
6
+ require 'net/http'
7
+ require 'cijoe/build'
8
+ require 'choice'
9
+
10
+ Choice.options do
11
+ header ''
12
+ header 'Specific options:'
13
+
14
+ option :host do
15
+ short '-h'
16
+ long '--host=HOST'
17
+ desc 'The hostname or ip of the host running buildboard (default 127.0.0.1)'
18
+ default '127.0.0.1'
19
+ end
20
+
21
+ option :port do
22
+ short '-p'
23
+ long '--port=PORT'
24
+ desc 'The port buildboard is running on (default 5678)'
25
+ cast Integer
26
+ default 5678
27
+ end
28
+
29
+ option :directory do
30
+ short '-d'
31
+ long '--directory=DIRECTORY'
32
+ desc 'The directory containing the CI Joe repository'
33
+ end
34
+
35
+ separator ''
36
+ separator 'Common options: '
37
+
38
+ option :help do
39
+ long '--help'
40
+ desc 'Show this message'
41
+ end
42
+ end
43
+
44
+ puts "You must supply a directory" and exit 1 unless Choice.choices[:directory]
45
+
46
+ build_file = File.join(Choice.choices[:directory], '.git', 'builds', 'last')
47
+ raise("Couldn't find file #{build_file}") unless File.exists?(build_file)
48
+ build = CIJoe::Build.load(build_file)
49
+ Net::HTTP.post_form(URI.parse("http://#{Choice.choices[:host]}:#{Choice.choices[:port]}/"),
50
+ {
51
+ :output => build.output,
52
+ :status => build.status == :failed ? 'failed' : 'success',
53
+ :sha => build.sha,
54
+ :started_at => build.started_at,
55
+ :finished_at => build.finished_at,
56
+ :project => build.project,
57
+ :git => `git log -1 #{build.sha}`
58
+ })
@@ -0,0 +1,133 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'yaml'
4
+ require 'fileutils'
5
+
6
+ class Build < Struct.new(:sha, :started_at, :finished_at, :status, :output, :project, :path, :git)
7
+ class << self
8
+ def load_file(filename)
9
+ build_data = YAML::load_file(filename)
10
+ new(build_data['sha'],
11
+ Time.parse(build_data['started_at']),
12
+ Time.parse(build_data['finished_at']),
13
+ build_data['status'],
14
+ build_data['output'],
15
+ build_data['project'],
16
+ filename,
17
+ build_data['git'])
18
+ end
19
+ end
20
+
21
+ def css_class
22
+ status
23
+ end
24
+
25
+ def file
26
+ File.basename(path)
27
+ end
28
+
29
+ def author
30
+ git.match(/Author: (.*?) \</).to_a[1]
31
+ end
32
+ end
33
+
34
+ class Builder
35
+ class << self
36
+ def projects
37
+ Dir[File.join(build_dir, '*')].map{|project|
38
+ project_name = project.gsub("#{build_dir}/", '')
39
+ last_build = Dir[File.join(project, '*')].last
40
+ Build.load_file(last_build)
41
+ }
42
+ end
43
+
44
+ def find(projectname, filename)
45
+ Build.load_file(File.join(build_dir, sanitize_filename(projectname), sanitize_filename(filename)))
46
+ end
47
+
48
+ def builds_for(projectname)
49
+ Dir[File.join(build_dir, sanitize_filename(projectname), '*-*-*')].reverse[0..9].map{|build|
50
+ Build.load_file(build)
51
+ }
52
+ end
53
+
54
+ # Borrowed from the Rails security guide:
55
+ # http://guides.rubyonrails.org/security.html#file-uploads
56
+ def sanitize_filename(filename)
57
+ name = filename.strip
58
+ # NOTE: File.basename doesn't work right with Windows paths on Unix
59
+ # get only the filename, not the whole path
60
+ name.gsub! /^.*(\\|\/)/, ''
61
+ # Finally, replace all non alphanumeric, underscore
62
+ # or periods with underscore
63
+ name.gsub! /[^\w\.\-]/, '_'
64
+ name
65
+ end
66
+
67
+ def builds
68
+ Dir[File.join(build_dir, '**', '*-*-*')].map{|build|
69
+ match = build.match(/.*\/(.*)-(.*)-(.*)/)
70
+ { :started => Time.at(match[1].to_i),
71
+ :sha => match[2],
72
+ :status => match[3],
73
+ :integrity_status => (match[3] == 'failure' ? 'failed' : 'success')
74
+ }
75
+ }
76
+ end
77
+
78
+ def build_dir
79
+ File.join(ENV['HOME'], '.buildboard')
80
+ end
81
+ end
82
+
83
+ def initialize(params)
84
+ @params = params
85
+ end
86
+
87
+ def project_dir
88
+ File.join(self.class.build_dir, @params[:project])
89
+ end
90
+
91
+ def build_file
92
+ started = Time.parse(@params[:started_at]).to_i
93
+ File.join(project_dir, "#{started}-#{@params[:sha][0..7]}-#{@params[:status]}")
94
+ end
95
+
96
+ def dump
97
+ FileUtils.mkdir_p(project_dir)
98
+ File.open(build_file, "w") do |file|
99
+ YAML::dump(@params, file)
100
+ end
101
+ end
102
+ end
103
+
104
+ class Buildboard < Sinatra::Base
105
+ helpers do
106
+ include Rack::Utils
107
+ alias_method :h, :escape_html
108
+ end
109
+
110
+ set :public, File.dirname(__FILE__) + '/../public'
111
+ set :views, File.dirname(__FILE__) + '/../views'
112
+
113
+ get '/' do
114
+ @builds = Builder.projects
115
+ erb :index
116
+ end
117
+
118
+ get /\/(.*)\/(.*)/ do |projectname, sha|
119
+ @build = Builder.find(projectname, sha)
120
+ erb :build
121
+ end
122
+
123
+ get /\/(.*)/ do |projectname|
124
+ @builds = Builder.builds_for(projectname)
125
+ @projectname = projectname
126
+ erb :project
127
+ end
128
+
129
+ post '/' do
130
+ Builder.new(params).dump
131
+ "Alrighty, Joe"
132
+ end
133
+ end
@@ -0,0 +1,82 @@
1
+ /* --------------------------------------------------------------
2
+
3
+ buttons.css
4
+ * Gives you some great CSS-only buttons.
5
+
6
+ Created by Kevin Hale [particletree.com]
7
+ * particletree.com/features/rediscovering-the-button-element
8
+
9
+ See Readme.txt in this folder for instructions.
10
+
11
+ -------------------------------------------------------------- */
12
+
13
+ button {
14
+ display:block;
15
+ float:left;
16
+ margin:0 0.583em 0.667em 0;
17
+ padding:5px 10px 5px 7px; /* Links */
18
+
19
+ border:1px solid #dedede;
20
+ border-top:1px solid #eee;
21
+ border-left:1px solid #eee;
22
+
23
+ background-color:#f5f5f5;
24
+ font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
25
+ font-size:100%;
26
+ line-height:130%;
27
+ text-decoration:none;
28
+ font-weight:bold;
29
+ color:#565656;
30
+ cursor:pointer;
31
+ }
32
+ button {
33
+ width:auto;
34
+ overflow:visible;
35
+ padding:4px 10px 3px 7px; /* IE6 */
36
+ }
37
+ button[type] {
38
+ padding:4px 10px 4px 7px; /* Firefox */
39
+ line-height:17px; /* Safari */
40
+ }
41
+ *:first-child+html button[type] {
42
+ padding:4px 10px 3px 7px; /* IE7 */
43
+ }
44
+ button img {
45
+ margin:0 3px -3px 0 !important;
46
+ padding:0;
47
+ border:none;
48
+ width:16px;
49
+ height:16px;
50
+ float:none;
51
+ }
52
+
53
+
54
+ /* Button colors
55
+ -------------------------------------------------------------- */
56
+
57
+ /* Standard */
58
+ button:hover {
59
+ background-color:#dff4ff;
60
+ border:1px solid #c2e1ef;
61
+ color:#336699;
62
+ }
63
+
64
+ /* Positive */
65
+ body .positive {
66
+ color:#529214;
67
+ }
68
+ button.positive:hover {
69
+ background-color:#E6EFC2;
70
+ border:1px solid #C6D880;
71
+ color:#529214;
72
+ }
73
+
74
+ /* Negative */
75
+ body .negative {
76
+ color:#d12f19;
77
+ }
78
+ button.negative:hover {
79
+ background:#fbe3e4;
80
+ border:1px solid #fbc2c4;
81
+ color:#d12f19;
82
+ }
File without changes
@@ -0,0 +1,354 @@
1
+ html {
2
+ background-color: #e0e0e0; }
3
+
4
+ body {
5
+ font-size: 100%;
6
+ font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
7
+ color: #333333; }
8
+
9
+ a {
10
+ color: #ed1556;
11
+ text-decoration: none; }
12
+ a:hover {
13
+ color: white;
14
+ background-color: #ed1556; }
15
+
16
+ #header, #content, #footer {
17
+ width: 40em;
18
+ margin: 0 auto;
19
+ background: #eeeeee;
20
+ padding: 0 2em;
21
+ z-index: 0;
22
+ position: relative;
23
+ font-size: 1em; }
24
+
25
+ #header {
26
+ background: white; }
27
+ #header h1 {
28
+ font-weight: bold;
29
+ font-size: 1.5em; }
30
+ #header address.watermark {
31
+ position: absolute;
32
+ font-weight: bold;
33
+ right: 3em;
34
+ top: 0;
35
+ font-size: .75em;
36
+ color: #cccccc; }
37
+ #header address.watermark a {
38
+ color: #cccccc;
39
+ font-weight: bold;
40
+ font-size: 2em; }
41
+ #header address.watermark a:hover {
42
+ background: transparent;
43
+ color: #aaaaaa; }
44
+
45
+ #content {
46
+ padding-top: 1em;
47
+ padding-bottom: 2em; }
48
+ #content strong {
49
+ font-weight: bold; }
50
+ #content em {
51
+ font-style: italic; }
52
+ #content h1, #content h2, #content h3, #content h4, #content h5, #content h6 {
53
+ color: #4e4e4e; }
54
+ #content h1 {
55
+ font-size: 2em;
56
+ font-weight: bold;
57
+ margin-bottom: .75em;
58
+ padding: .25em 0;
59
+ line-height: 1.2;
60
+ border-bottom: 1px solid silver; }
61
+ #content h2 {
62
+ font-weight: bold;
63
+ font-size: 1.5em;
64
+ margin: 1em 0 .2em; }
65
+ #content h3 {
66
+ font-weight: bold;
67
+ font-size: 1.25em;
68
+ margin: .25em 0; }
69
+ #content h4, #content h5, #content h6 {
70
+ font-weight: bold;
71
+ margin-top: .5em; }
72
+ #content code, #content pre, #content textarea, #content input {
73
+ font-family: Monaco, Deja Vu Sans Mono, Inconsolata, Consolas, monospace; }
74
+ #content pre {
75
+ margin: .5em;
76
+ padding: .5em; }
77
+ #content form p {
78
+ margin-top: 1em;
79
+ position: relative; }
80
+ #content form p.checkbox label {
81
+ margin-top: 0 !important; }
82
+ #content form input.text, #content form textarea, #content form select {
83
+ width: 30em;
84
+ padding: .2em .4em;
85
+ color: #4e4e4e; }
86
+ #content form input.text {
87
+ height: 1.4em; }
88
+ #content form label {
89
+ float: left;
90
+ display: block;
91
+ margin-top: .5em;
92
+ width: 8em;
93
+ margin-right: .75em; }
94
+ #content form .with_errors label {
95
+ background: red;
96
+ color: white;
97
+ position: relative;
98
+ top: -.7em; }
99
+ #content form .with_errors.required label {
100
+ position: static;
101
+ margin-right: .25em;
102
+ padding: 0 .2em; }
103
+ #content form .with_errors input, #content form .with_errors textarea, #content form .with_errors select {
104
+ border: 2px solid #f22;
105
+ background: #fee;
106
+ color: #222222; }
107
+ #content form .required label {
108
+ float: none;
109
+ display: block;
110
+ width: auto;
111
+ position: relative;
112
+ font-weight: bold;
113
+ margin-top: 1em;
114
+ text-indent: -.65em; }
115
+ #content form .required label:before {
116
+ content: "* ";
117
+ color: #ed1556; }
118
+ #content form .required input.text {
119
+ width: 25.6em;
120
+ font-size: 24px;
121
+ font-weight: bold; }
122
+ #content form .normal {
123
+ margin-top: 2em; }
124
+ #content form h2.notifier label {
125
+ float: none;
126
+ width: auto;
127
+ margin-right: 0; }
128
+ #content form h2.notifier label .warning {
129
+ font-size: .5em;
130
+ font-weight: normal;
131
+ color: #999999; }
132
+ #content form fieldset {
133
+ padding-bottom: 1em;
134
+ margin-left: 1.35em;
135
+ border-bottom: 1px solid silver;
136
+ margin-bottom: 1em; }
137
+ #content form fieldset h3 {
138
+ margin-top: 1em;
139
+ margin-bottom: 0; }
140
+ #content form fieldset p.normal {
141
+ margin-top: 1em; }
142
+ #content form fieldset p label {
143
+ width: 6.7em; }
144
+ #content form p.submit {
145
+ margin-top: 2em; }
146
+ #content form p.submit:after {
147
+ display: block;
148
+ clear: both;
149
+ float: none;
150
+ content: ".";
151
+ text-indent: -9999em;
152
+ text-align: left; }
153
+ #content form p.submit.destroy button, #content form p.submit.manual-build button {
154
+ float: none;
155
+ display: inline; }
156
+ #content form p.submit.manual-build button {
157
+ margin-right: 0; }
158
+ #content #build form, #content #last_build form {
159
+ font-size: .75em; }
160
+ #content #build form p.submit, #content #last_build form p.submit {
161
+ margin: 0;
162
+ padding: 0;
163
+ position: absolute;
164
+ right: .5em;
165
+ top: 1.25em; }
166
+ #content .blank_slate p, #content .error p {
167
+ position: relative;
168
+ top: .3em; }
169
+ #content .blank_slate h1, #content .error h1 {
170
+ border-width: 0;
171
+ margin: 0;
172
+ padding: 0; }
173
+ #content .blank_slate h1 button, #content .error h1 button {
174
+ float: none;
175
+ border: 0 none;
176
+ background: transparent;
177
+ display: inline;
178
+ color: #ed1556;
179
+ padding: 0.25em 0;
180
+ margin: 0; }
181
+ #content .blank_slate h1 button:hover, #content .error h1 button:hover {
182
+ background: #ed1556;
183
+ color: white; }
184
+ #content .error dt {
185
+ margin-top: 1.4em;
186
+ margin-bottom: .3em;
187
+ font-size: 1.75em;
188
+ font-family: Georgia, Times New Roman, serif; }
189
+ #content .error dd {
190
+ line-height: 1.4; }
191
+ #content .error .backtrace {
192
+ margin: 1em 0;
193
+ overflow: "scroll";
194
+ height: 30em;
195
+ border: 1px solid silver;
196
+ line-height: 1.6; }
197
+ #content #projects {
198
+ margin: 1em 0 2em;
199
+ border-top: 1px solid silver; }
200
+ #content #projects li {
201
+ position: relative;
202
+ border-bottom: 1px solid silver; }
203
+ #content #projects li.odd {
204
+ background: #e6e6e6; }
205
+ #content #projects li a {
206
+ font-size: 2em;
207
+ padding: .25em;
208
+ line-height: 1.2;
209
+ font-weight: bold;
210
+ display: block; }
211
+ #content #projects li a.success {
212
+ color: #337022; }
213
+ #content #projects li a.failed {
214
+ color: #ff1100; }
215
+ #content #projects li a.building {
216
+ color: #777777; }
217
+ #content #projects li .meta {
218
+ position: absolute;
219
+ right: .6em;
220
+ top: 1.5em;
221
+ font-size: 0.8em;
222
+ color: #999999;
223
+ text-align: right; }
224
+ #content #projects li.success .meta {
225
+ color: #337022; }
226
+ #content #projects li.failed .meta {
227
+ color: #ff1100; }
228
+ #content #projects li.building .meta {
229
+ color: #777777; }
230
+ #content #previous_builds li a {
231
+ display: block;
232
+ padding: .25em;
233
+ margin-bottom: .25em;
234
+ border-width: 1px;
235
+ border-style: solid; }
236
+ #content #previous_builds li a strong {
237
+ font-size: 1.3em; }
238
+ #content #previous_builds li a .attribution {
239
+ font-size: .9em; }
240
+ #content #projects li.success a, #content #previous_builds li.success a {
241
+ background-color: #bbf8aa;
242
+ border-color: #99d688;
243
+ color: #337022; }
244
+ #content #projects li.success a .attribution, #content #previous_builds li.success a .attribution {
245
+ color: #77b466; }
246
+ #content #projects li.success a:hover, #content #previous_builds li.success a:hover {
247
+ background-color: #ddffcc; }
248
+ #content #projects li.failed a, #content #previous_builds li.failed a {
249
+ background-color: #ffbbaa;
250
+ border-color: #dd9988;
251
+ color: #ff1100; }
252
+ #content #projects li.failed a .attribution, #content #previous_builds li.failed a .attribution {
253
+ color: #bb7766; }
254
+ #content #projects li.failed a:hover, #content #previous_builds li.failed a:hover {
255
+ background-color: #ffddcc; }
256
+ #content #projects li.building a, #content #previous_builds li.building a {
257
+ background-color: #cccccc;
258
+ border-color: #aaaaaa;
259
+ color: #777777; }
260
+ #content #projects li.building a .attribution, #content #previous_builds li.building a .attribution {
261
+ color: #888888; }
262
+ #content #projects li.building a:hover, #content #previous_builds li.building a:hover {
263
+ background-color: #eeeeee; }
264
+ #content #build, #content #last_build {
265
+ position: relative; }
266
+ #content #build h1, #content #build blockquote, #content #last_build h1, #content #last_build blockquote {
267
+ border-width: 0 1px;
268
+ border-style: solid; }
269
+ #content #build h1, #content #last_build h1 {
270
+ border-top-width: 1px; }
271
+ #content #build blockquote, #content #last_build blockquote {
272
+ bottom-bottom-width: 1px;
273
+ line-height: 1.4; }
274
+ #content #build.success h1, #content #build.success blockquote, #content #last_build.success h1, #content #last_build.success blockquote {
275
+ background-color: #bbf8aa;
276
+ border-color: #99d688 #ccffbb #ccffbb #99d688; }
277
+ #content #build.success h1, #content #last_build.success h1 {
278
+ color: #337022; }
279
+ #content #build.success .meta, #content #last_build.success .meta {
280
+ color: #77b466; }
281
+ #content #build.failed h1, #content #build.failed blockquote, #content #last_build.failed h1, #content #last_build.failed blockquote {
282
+ background-color: #ffbbaa;
283
+ border-color: #dd9988 #ffccbb #ffccbb #dd9988; }
284
+ #content #build.failed h1, #content #last_build.failed h1 {
285
+ color: #ff1100; }
286
+ #content #build.failed .meta, #content #last_build.failed .meta {
287
+ color: #bb7766; }
288
+ #content #build.building h1, #content #build.building blockquote, #content #last_build.building h1, #content #last_build.building blockquote {
289
+ background-color: #cccccc;
290
+ border-color: #aaaaaa #dddddd #dddddd #aaaaaa; }
291
+ #content #build.building h1, #content #last_build.building h1 {
292
+ color: #777777; }
293
+ #content #build.building .meta, #content #last_build.building .meta {
294
+ color: #333333; }
295
+ #content #build h1, #content #last_build h1 {
296
+ margin-top: .5em;
297
+ margin-bottom: 0;
298
+ padding: .25em;
299
+ color: #337022; }
300
+ #content #build blockquote, #content #last_build blockquote {
301
+ padding: .75em;
302
+ margin-bottom: 2em; }
303
+ #content #build blockquote .meta, #content #last_build blockquote .meta {
304
+ margin-top: 1em;
305
+ display: block;
306
+ font-size: .9em; }
307
+ #content #build pre.output, #content #last_build pre.output {
308
+ background: #111;
309
+ color: #fff;
310
+ padding: .5em;
311
+ overflow: auto;
312
+ max-height: 50em;
313
+ font-size: .825em; }
314
+ #content #build pre.output .color30, #content #last_build pre.output .color30 {
315
+ color: #333; }
316
+ #content #build pre.output .color31, #content #last_build pre.output .color31 {
317
+ color: #e33; }
318
+ #content #build pre.output .color32, #content #last_build pre.output .color32 {
319
+ color: #3e3; }
320
+ #content #build pre.output .color33, #content #last_build pre.output .color33 {
321
+ color: #ee3; }
322
+ #content #build pre.output .color34, #content #last_build pre.output .color34 {
323
+ color: #33e; }
324
+ #content #build pre.output .color35, #content #last_build pre.output .color35 {
325
+ color: #e3e; }
326
+ #content #build pre.output .color36, #content #last_build pre.output .color36 {
327
+ color: #3ee; }
328
+ #content #build pre.output .color37, #content #last_build pre.output .color37 {
329
+ color: #fff; }
330
+ #content #push_path {
331
+ display: block;
332
+ margin-top: 1em;
333
+ margin-left: 2em; }
334
+
335
+ a.success {
336
+ color: #bbf8aa; }
337
+ a.success:hover {
338
+ background-color: #bbf8aa;
339
+ color: white; }
340
+ a.failed {
341
+ color: #ffbbaa; }
342
+ a.failed:hover {
343
+ background-color: #ffbbaa;
344
+ color: white; }
345
+
346
+ #footer {
347
+ padding: 1.5em 2.5em;
348
+ border-top: 1px solid #ccc;
349
+ font-size: .8em;
350
+ width: 50em !important;
351
+ color: #666;
352
+ text-align: right; }
353
+ #footer strong {
354
+ font-weight: bold; }
@@ -0,0 +1,7 @@
1
+ /*
2
+ Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3
+ Code licensed under the BSD License:
4
+ http://developer.yahoo.net/yui/license.txt
5
+ version: 2.5.2
6
+ */
7
+ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;font-variant:normal;}sup {vertical-align:text-top;}sub {vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Buildboard" do
4
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'buildboard'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,7 @@
1
+ <div class='<%= build.status %>' id='build'>
2
+ <h1>Build <%= build.sha[0..7] %> <%= build.status %></h1>
3
+ <h2>Git Log:</h2>
4
+ <pre class='output'><%= h(build.git) %></pre>
5
+ <h2>Build Output:</h2>
6
+ <pre class='output'><%= h(build.output) %></pre>
7
+ </div>
@@ -0,0 +1,5 @@
1
+ <li class='<%= build.css_class %>'>
2
+ <a href='/<%= link %>'><%= title %></a>
3
+ <div class='meta'><%= build.finished_at.strftime("%b %d %H:%M") %>
4
+ </div>
5
+ </li>
@@ -0,0 +1,16 @@
1
+ <div id='header'>
2
+ <h1>
3
+ <% header_items.each do |item| %>
4
+ <% if item == header_items.last %>
5
+ <%= item %>
6
+ <% elsif item == header_items.first %>
7
+ <a href="/"><%= item %></a> /
8
+ <% else %>
9
+ <a href="/<%= item %>"><%= item %></a> /
10
+ <% end%>
11
+ <% end %>
12
+ </h1>
13
+ <address class='watermark'>
14
+ <a href="/">buildboard</a>
15
+ </address>
16
+ </div>
@@ -0,0 +1,6 @@
1
+ <li class='<%= build.status %>'>
2
+ <a href='/<%= "#{build.project}/#{build.file}" %>'>
3
+ <strong class='build'>Build <%= build.sha[0..7] %></strong>
4
+ <span class='attribution'>by <%= build.author %> on <%= build.finished_at.strftime("%b %d") %></span>
5
+ </a>
6
+ </li>
@@ -0,0 +1,4 @@
1
+ <%= erb(:_header, :locals => { :header_items => [ 'projects', @build.project, @build.sha[0..7]]})%>
2
+ <div id='content'>
3
+ <%= erb(:_build, :layout => false, :locals => { :build => @build }) %>
4
+ </div>
@@ -0,0 +1,12 @@
1
+ <%= erb(:_header, :locals => { :header_items => [ 'projects' ]})%>
2
+ <div id='content'>
3
+ <ul id='projects'>
4
+ <% @builds.each do |build| %>
5
+ <%= erb(:_buildline,
6
+ :layout => false,
7
+ :locals => { :build => build,
8
+ :title => build.project,
9
+ :link => build.project }) %>
10
+ <% end %>
11
+ </ul>
12
+ </div>
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
5
+ <meta content='en' http-equiv='Content-Language' />
6
+ <title><%= @projectname %> | buildboard</title>
7
+ <link href='/reset.css' rel='stylesheet' type='text/css' />
8
+ <link href='/buttons.css' rel='stylesheet' type='text/css' />
9
+ <link href='/integrity.css' rel='stylesheet' type='text/css' />
10
+ </head>
11
+ <body>
12
+ <%= yield %>
13
+ </body>
14
+ </html>
@@ -0,0 +1,15 @@
1
+ <%= erb(:_header, :locals => { :header_items => [ 'projects', @projectname] })%>
2
+ <div id='content'>
3
+ <% build = @builds.shift %>
4
+ <%= erb(:_build, :locals => { :build => build }) %>
5
+ <h2>Builds</h2>
6
+ <ul id='previous_builds'>
7
+ <% @builds.each do |build| %>
8
+ <%= erb(:_smallbuildline,
9
+ :layout => false,
10
+ :locals => { :build => build,
11
+ :title => build.sha[0..7],
12
+ :link => "#{build.project}/#{build.file}" }) %>
13
+ <% end %>
14
+ </ul>
15
+ </div>
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buildboard
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Jacob Atzen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-01 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ description: Buildboard is an Integrity style dashboard for CI Joe
35
+ email: jacob@incremental.dk
36
+ executables:
37
+ - buildboard
38
+ - update-buildboard
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.md
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.md
49
+ - Rakefile
50
+ - VERSION
51
+ - bin/buildboard
52
+ - bin/update-buildboard
53
+ - lib/buildboard.rb
54
+ - public/buttons.css
55
+ - public/favicon.ico
56
+ - public/integrity.css
57
+ - public/reset.css
58
+ - spec/buildboard_spec.rb
59
+ - spec/spec.opts
60
+ - spec/spec_helper.rb
61
+ - views/_build.erb
62
+ - views/_buildline.erb
63
+ - views/_header.erb
64
+ - views/_smallbuildline.erb
65
+ - views/build.erb
66
+ - views/index.erb
67
+ - views/layout.erb
68
+ - views/project.erb
69
+ has_rdoc: true
70
+ homepage: http://github.com/jacobat/buildboard
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options:
75
+ - --charset=UTF-8
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.6
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Integrity style dashboard for CI Joe
99
+ test_files:
100
+ - spec/buildboard_spec.rb
101
+ - spec/spec_helper.rb