ciquantum 0.0.10 → 0.0.11

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/ciquantum.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |gem|
25
25
  gem.add_runtime_dependency 'sinatra'
26
26
  gem.add_runtime_dependency 'choice'
27
27
  gem.add_runtime_dependency 'pony'
28
- gem.add_runtime_dependency 'sq_auth', '>= 0.0.24'
28
+ gem.add_runtime_dependency 'sq_auth', '>= 0.0.25'
29
29
  gem.add_development_dependency 'rack-test'
30
30
  gem.add_development_dependency 'mocha'
31
31
 
@@ -29,6 +29,10 @@ module CIQuantum
29
29
  finished_at - started_at
30
30
  end
31
31
 
32
+ def id
33
+ "#{sha}-#{finished_at.to_i}"
34
+ end
35
+
32
36
  def short_sha
33
37
  if sha
34
38
  sha[0,7]
@@ -42,7 +46,7 @@ module CIQuantum
42
46
  end
43
47
 
44
48
  def env_output
45
- out = clean_output
49
+ out = output # clean_output
46
50
  out.size > 100_000 ? out[-100_000,100_000] : out
47
51
  end
48
52
 
@@ -51,6 +55,18 @@ module CIQuantum
51
55
  @commit ||= Commit.new(sha, user, project, project_path)
52
56
  end
53
57
 
58
+ def test_results
59
+ stat = { success: 0, failures:0, pending:0 }
60
+ clean_output.gsub(/(\d+) examples, (\d+) failures(?:, (\d+) pending)?/) do
61
+ stat[:success] += $1.to_i
62
+ stat[:failures] += $2.to_i
63
+ stat[:pending] += $3.to_i
64
+ end
65
+ res = "#{stat[:success]} examples, #{stat[:failures]} failures"
66
+ res += ", #{stat[:pending]} pending" if stat[:pending] > 0
67
+ res
68
+ end
69
+
54
70
  def dump file
55
71
  config = [user, project, started_at, finished_at, sha, status, output, pid, branch]
56
72
  data = YAML.dump(config)
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  module CIQuantum
2
4
  class Core
3
5
  attr_reader :user
@@ -5,9 +7,9 @@ module CIQuantum
5
7
  attr_reader :url
6
8
  attr_reader :current_build
7
9
  attr_reader :last_build
8
- attr_reader :campfire
9
10
  attr_reader :projectname
10
11
  attr_reader :coverage_path
12
+ attr_accessor :shared_path
11
13
 
12
14
  HistoryLimit = 10
13
15
 
@@ -63,6 +65,7 @@ module CIQuantum
63
65
  write_current_build
64
66
  write_last_build
65
67
  run_hook "postbuild"
68
+ save_coverage_for_build @last_build
66
69
 
67
70
  build(@queue.next_branch_to_build) if @queue.waiting?
68
71
  end
@@ -100,8 +103,8 @@ module CIQuantum
100
103
  def build!(branch=nil)
101
104
  @git_branch = branch
102
105
  build = @current_build
103
- run_hook "prebuild"
104
106
  git_update
107
+ run_hook "prebuild"
105
108
  output = ''
106
109
  build.sha = git_sha
107
110
  build.branch = git_branch
@@ -129,7 +132,7 @@ module CIQuantum
129
132
  # shellin' out
130
133
  def runner_command
131
134
  runner = repo_config.runner.to_s
132
- runner == '' ? "rake -s test:units" : runner
135
+ runner == '' ? "rake -s --color test:units" : runner
133
136
  end
134
137
 
135
138
  def git_update
@@ -148,7 +151,8 @@ module CIQuantum
148
151
 
149
152
  # massage our repo
150
153
  def run_hook(hook)
151
- if File.exists?(file=path_in_project(".git/hooks/#{hook}")) && File.executable?(file)
154
+ file = path_in_project(".git/hooks/#{hook}")
155
+ if File.exists?(file) && File.executable?(file)
152
156
  data =
153
157
  if @last_build && @last_build.commit
154
158
  {
@@ -184,10 +188,26 @@ module CIQuantum
184
188
  @current_build = nil
185
189
  end
186
190
 
187
- def path_in_project(path)
191
+ def path_in_project path
188
192
  File.join(@project_path, path)
189
193
  end
190
194
 
195
+ def coverage_for_build build
196
+ File.join build.id, "coverage"
197
+ end
198
+
199
+ def coverage_path_for_build build
200
+ File.join @shared_path, coverage_for_build(build)
201
+ end
202
+
203
+ def save_coverage_for_build build
204
+ return unless @coverage_path
205
+ build_coverage_path = coverage_path_for_build(build)
206
+ puts "Coverage path: #{build_coverage_path}"
207
+ FileUtils.mkdir_p build_coverage_path
208
+ FileUtils.cp_r "#{path_in_project(@coverage_path)}/.", build_coverage_path
209
+ end
210
+
191
211
  def repo_config
192
212
  Config.ciquantum(@project_path)
193
213
  end
@@ -207,6 +227,10 @@ module CIQuantum
207
227
  @git_branch = (branch == '' ? "master" : branch)
208
228
  end
209
229
 
230
+ def is_current_git_branch? branch
231
+ return branch.eql? git_branch
232
+ end
233
+
210
234
  def git_sha
211
235
  `cd #{@project_path} && git rev-parse origin/#{git_branch}`.chomp
212
236
  end
@@ -224,7 +248,20 @@ module CIQuantum
224
248
  end
225
249
 
226
250
  def read_build_by_index index
227
- read_build old_builds[index] if old_builds[index]
251
+ old_builds[index] ? read_build(old_builds[index]) : nil
252
+ end
253
+
254
+ def active_builds
255
+ active_builds = []
256
+ old_builds.each do |build_file|
257
+ build = read_build(build_file)
258
+ active_builds << build
259
+ if build.status == :worked
260
+ remove_builds_from build
261
+ break
262
+ end
263
+ end
264
+ active_builds
228
265
  end
229
266
 
230
267
  def old_builds
@@ -254,12 +291,12 @@ module CIQuantum
254
291
  remove_unused_build
255
292
  end
256
293
 
257
- def remove_unused_build
258
- builds = old_builds
259
- if builds.size > HistoryLimit
260
- builds[HistoryLimit..builds.size].each do |file|
261
- file = path_in_project(".git/builds/#{file}")
262
- File.delete file if File.exists? file
294
+ def remove_builds_from limit_build
295
+ old_builds.each do |build_file|
296
+ build = read_build(build_file)
297
+ if build.finished_at < limit_build.finished_at
298
+ FileUtils.rm_r build_file
299
+ FileUtils.rm_r coverage_path_for_build build_file
263
300
  end
264
301
  end
265
302
  end
@@ -0,0 +1,6 @@
1
+ function toggleVisibility(id) {
2
+ var e = document.getElementById(id);
3
+ if(!e) return true;
4
+ e.style.display = (e.style.display == "none" ? "block" : "none")
5
+ return true;
6
+ }
@@ -35,18 +35,6 @@ h1 a {
35
35
  color: #000;
36
36
  }
37
37
 
38
- .failed, .color31 {
39
- color: red !important;
40
- }
41
-
42
- .worked, .color32 {
43
- color: green !important;
44
- }
45
-
46
- .errored, .color33 {
47
- color: yellow !important;
48
- }
49
-
50
38
  p {
51
39
  margin: 1em 0;
52
40
  }
@@ -79,16 +67,16 @@ ul.posts {
79
67
  margin-bottom: 2em;
80
68
  }
81
69
 
82
- ul.posts li {
83
- line-height: 1.75em;
84
- }
70
+ ul.posts li {
71
+ line-height: 1.75em;
72
+ }
85
73
 
86
- ul.posts .date,
87
- ul.posts .duration {
88
- color: #aaa;
89
- font-family: Monaco, "Courier New", monospace;
90
- font-size: 80%;
91
- }
74
+ ul.posts .date,
75
+ ul.posts .duration {
76
+ color: #aaa;
77
+ font-family: Monaco, "Courier New", monospace;
78
+ font-size: 80%;
79
+ }
92
80
 
93
81
  /*****************************************************************************/
94
82
  /*
@@ -110,97 +98,117 @@ ul.posts {
110
98
  margin-bottom: 2em;
111
99
  }
112
100
 
113
- .site .title a {
114
- color: #a00;
115
- text-decoration: none;
116
- }
101
+ .site .title a {
102
+ color: #a00;
103
+ text-decoration: none;
104
+ }
117
105
 
118
- .site .title a:hover {
119
- color: black;
120
- }
106
+ .site .title a:hover {
107
+ color: black;
108
+ }
121
109
 
122
- .site .title .extra {
123
- color: #aaa;
124
- text-decoration: none;
125
- margin-left: 1em;
126
- font-size: 0.9em;
127
- }
110
+ .site .title .extra {
111
+ color: #aaa;
112
+ text-decoration: none;
113
+ margin-left: 1em;
114
+ font-size: 0.9em;
115
+ }
128
116
 
129
- .site .title a.extra:hover {
130
- color: black;
131
- }
117
+ .site .title a.extra:hover {
118
+ color: black;
119
+ }
132
120
 
133
- .site .meta {
134
- color: #aaa;
135
- }
121
+ .site .meta {
122
+ color: #aaa;
123
+ }
136
124
 
137
- .site .footer {
138
- font-size: 80%;
139
- color: #666;
140
- border-top: 4px solid #eee;
141
- margin-top: 2em;
142
- overflow: hidden;
143
- }
125
+ .site .footer {
126
+ font-size: 80%;
127
+ color: #666;
128
+ border-top: 4px solid #eee;
129
+ margin-top: 2em;
130
+ overflow: hidden;
131
+ }
144
132
 
145
- .site .footer .contact {
146
- float: left;
147
- margin-right: 3em;
148
- }
133
+ .site .footer .contact {
134
+ float: left;
135
+ margin-right: 3em;
136
+ }
149
137
 
150
- .site .footer .contact a {
151
- color: #8085C1;
152
- }
138
+ .site .footer .contact a {
139
+ color: #8085C1;
140
+ }
153
141
 
154
- .site .footer .rss {
155
- margin-top: 1.1em;
156
- margin-right: -.2em;
157
- float: right;
158
- }
142
+ .site .footer .rss {
143
+ margin-top: 1.1em;
144
+ margin-right: -.2em;
145
+ float: right;
146
+ }
159
147
 
160
- .site .footer .rss img {
161
- border: 0;
162
- }
148
+ .site .footer .rss img {
149
+ border: 0;
150
+ }
163
151
 
164
152
  /*****************************************************************************/
165
153
  /*
166
- /* Posts
154
+ /* Builds
167
155
  /*
168
156
  /*****************************************************************************/
169
157
 
170
- #post {
158
+ span.failed, .color36 {
159
+ color: red !important;
160
+ }
171
161
 
162
+ span.worked, .color32 {
163
+ color: green !important;
172
164
  }
173
165
 
174
- /* standard */
166
+ span.errored, .color33 {
167
+ color: yellow !important;
168
+ }
175
169
 
176
- #post pre {
177
- border: 1px solid #ddd;
178
- background-color: #eef;
179
- padding: 0 .4em;
170
+ div.build, div.commit, div.result {
171
+ border: 1px solid black;
172
+ background-color: #E0E0E0;
180
173
  }
181
174
 
182
- #post ul,
183
- #post ol {
184
- margin-left: 1.25em;
175
+ div.commit {
176
+ font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
185
177
  }
186
178
 
187
- #post code {
188
- border: 1px solid #ddd;
189
- background-color: #eef;
190
- font-size: 95%;
191
- padding: 0 .2em;
179
+ div.build div {
180
+ padding: 5px;
192
181
  }
193
182
 
194
- #post pre code {
195
- border: none;
196
- }
183
+ div.build {
184
+ padding: 0px;
185
+ margin: 30px 0px;
186
+ }
187
+
188
+ div.failed {
189
+ background-color: #CC3333;
190
+ }
191
+
192
+ div.worked {
193
+ background-color: #33CC33;
194
+ }
195
+
196
+ div.errored {
197
+ background-color: #CCCC33;
198
+ }
199
+
200
+ pre {
201
+ overflow: auto;
202
+ word-wrap: break-word;
203
+ }
197
204
 
198
205
  /* terminal */
199
206
 
200
207
  pre.terminal {
201
208
  border: 1px solid black;
202
- background-color: #333;
209
+ background-color: #E0E0E0;
203
210
  color: white;
211
+ margin: 0px;
204
212
  padding: 5px;
205
213
  overflow: auto;
206
214
  word-wrap: break-word;
@@ -1,5 +1,6 @@
1
1
  require 'erb'
2
2
  require 'json'
3
+ require 'fileutils'
3
4
 
4
5
  require 'sinatra'
5
6
  require 'sq_auth'
@@ -33,10 +34,15 @@ module CIQuantum
33
34
  quantum.last_build.sha
34
35
  end
35
36
 
36
- get ["ci::view", "ci::change_branch"], '/?' do
37
+ get ["ci::view"], '/?' do
37
38
  erb(:template, {}, :quantum => quantum, :can_change_branch => accessed_by?("ci::change_branch"))
38
39
  end
39
40
 
41
+ get ["ci::view"], "/*/coverage/?" do |build_id|
42
+ puts "Public folder: #{settings.public_folder}"
43
+ redirect "/#{build_id}/coverage/index.html"
44
+ end
45
+
40
46
  sq_auth_access do
41
47
  access_action "/build" do
42
48
  execute_for "ci::view"
@@ -47,7 +53,7 @@ module CIQuantum
47
53
  end
48
54
 
49
55
  post '/build' do
50
- quantum.build quantum.repo_config.branch
56
+ quantum.build quantum.git_branch
51
57
  redirect '/'
52
58
  end
53
59
 
@@ -80,8 +86,7 @@ module CIQuantum
80
86
  end
81
87
 
82
88
  get ["ci::view"], '/coverage?' do
83
- link_coverage_path
84
- redirect "coverage/index.html"
89
+ redirect "/#{quantum.last_build.sha}/coverage/index.html"
85
90
  end
86
91
 
87
92
  helpers do
@@ -110,10 +115,14 @@ module CIQuantum
110
115
  super
111
116
  check_project
112
117
  @quantum = CIQuantum.new(settings.project_path)
118
+ @quantum.shared_path = settings.public_folder
113
119
  end
114
120
 
115
121
  def self.start(host, port, project_path)
122
+ git_path = File.join(project_path, ".git")
123
+ FileUtils.cp_r settings.public_folder, git_path
116
124
  set :project_path, project_path
125
+ set :public_folder, "#{git_path}/public"
117
126
  CIQuantum::Server.run! :host => host, :port => port
118
127
  end
119
128
 
@@ -122,16 +131,6 @@ module CIQuantum
122
131
  self.new
123
132
  end
124
133
 
125
- def link_coverage_path
126
- public_coverage_path = File.join settings.public_folder, "coverage"
127
- project_coverage_path = File.join settings.project_path, quantum.coverage_path
128
-
129
- File.unlink public_coverage_path if File.exists? public_coverage_path
130
- if !quantum.coverage_path.empty? and File.exists? project_coverage_path
131
- File.symlink project_coverage_path, public_coverage_path
132
- end
133
- end
134
-
135
134
  def self.project_path=(project_path)
136
135
  set :project_path, Proc.new{project_path}, true
137
136
  end
@@ -1,3 +1,3 @@
1
1
  module CIQuantum
2
- Version = VERSION = "0.0.10"
2
+ Version = VERSION = "0.0.11"
3
3
  end
@@ -0,0 +1,22 @@
1
+
2
+ <div class="build" >
3
+ <div class="<%= build.status %>">
4
+ <b><%= build.branch %></b> : <%= build.status %> at <b><%= pretty_time(build.finished_at) %></b>. Build duration: <b><%= build.duration %></b> seconds.
5
+ </div>
6
+ <% if build.sha %>
7
+ <div class="commit">
8
+ Commit : <a href="<%= build.commit.url %>"><%= build.commit.sha %></a><br/>
9
+ Author : <%= build.commit.author %><br/>
10
+ Message: <pre><%= build.commit.message %></pre>
11
+ </div>
12
+ <% end %>
13
+ <div class="results">
14
+ <h4 class="result">>Test results: <%= build.test_results %></h4>
15
+ <a href="<%= quantum.coverage_for_build(build) %>">Show coverage</a> |
16
+ <a href="#" onclick="toggleVisibility('<%= build.id %>')">Show output</a>
17
+ <div id="<%= build.id %>" style="display:none">
18
+ <pre class="terminal"><code><%= ansi_color_codes h(build.output) %></code></pre>
19
+ </div>
20
+
21
+ </div>
22
+ </div>
@@ -1,16 +1,19 @@
1
- { "jobs": [
2
- <% if quantum.last_build %>
3
- {"name":"<%= quantum.projectname || quantum.project %>",
4
- "url":"<%= quantum.url %>",
5
- "color":"<%= quantum.last_build.status.to_s == "failed" ? 'red' : 'blue' %>",
6
- "status":"<%= quantum.last_build.status %>",
7
- "started_at":"<%= pretty_time(quantum.last_build.started_at) %>",
8
- "finished_at":"<%= pretty_time(quantum.last_build.finished_at) %>",
9
- "duration":"<%= quantum.last_build.duration if quantum.last_build.duration %>",
10
- "sha":"<%= quantum.last_build.sha %>",
11
- "short_sha":"<%= quantum.last_build.short_sha %>",
12
- "commit_url":"<%= quantum.last_build.commit.url if quantum.last_build.commit %>",
13
- "branch":"<%= quantum.last_build.branch %>"
14
- }
15
- <% end %>
16
- ]}
1
+ {
2
+ "jobs": [
3
+ <% if quantum.last_build %>
4
+ {
5
+ "name":"<%= quantum.projectname || quantum.project %>",
6
+ "url":"<%= quantum.url %>",
7
+ "color":"<%= quantum.last_build.status.to_s == "failed" ? 'red' : 'blue' %>",
8
+ "status":"<%= quantum.last_build.status %>",
9
+ "started_at":"<%= pretty_time(quantum.last_build.started_at) %>",
10
+ "finished_at":"<%= pretty_time(quantum.last_build.finished_at) %>",
11
+ "duration":"<%= quantum.last_build.duration if quantum.last_build.duration %>",
12
+ "sha":"<%= quantum.last_build.sha %>",
13
+ "short_sha":"<%= quantum.last_build.short_sha %>",
14
+ "commit_url":"<%= quantum.last_build.commit.url if quantum.last_build.commit %>",
15
+ "branch":"<%= quantum.last_build.branch %>"
16
+ }
17
+ <% end %>
18
+ ]
19
+ }
@@ -2,6 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <link href="<%= ciquantum_root %>/screen.css" media="screen" rel="stylesheet" type="text/css" />
5
+ <script type="text/JavaScript" src="<%= ciquantum_root %>/javascript.js"></script>
5
6
  <title><%= h(quantum.projectname) %>: CI Quantum</title>
6
7
  </head>
7
8
  <body>
@@ -35,7 +36,7 @@
35
36
  <form method="POST" action="/switch_branch">
36
37
  <select name="branch">
37
38
  <% for @branch in quantum.git_branches %>
38
- <option value="<%= @branch %>" <%= 'selected="selected"' if (@branch == quantum.git_branch) %>>"<%= @branch %>"</option>
39
+ <option value="<%= @branch %>" <%= 'selected="selected"' if quantum.is_current_git_branch?(@branch) %>>"<%= @branch %>"</option>
39
40
  <% end %>
40
41
  </select>
41
42
  <input type="submit" name="switch" value="Switch branch and build"/>
@@ -43,25 +44,10 @@
43
44
  <% end %>
44
45
  </li>
45
46
  <% end %>
46
-
47
- <% if quantum.last_build %>
48
- <li>
49
- <span class="date"><%= pretty_time(quantum.last_build.finished_at) %></span> &raquo;
50
- <% if quantum.last_build.sha %>
51
- Built <%= quantum.last_build.branch %> at <a href="<%= quantum.last_build.commit.url %>"><%= quantum.last_build.short_sha %></a>
52
- <% end %>
53
- <span class="<%= quantum.last_build.status %>">(<%= quantum.last_build.status %>)</span>
54
-
55
- <% if quantum.last_build.duration %>
56
- in <span class="duration"><%= quantum.last_build.duration %></span> seconds.
57
- <% end %>
58
47
 
59
- <% if !quantum.coverage_path.empty? || true %>
60
- <span class="coverage"><a href="coverage">Code coverage</a>
61
- <% end %>
62
- </li>
63
- <% if quantum.last_build.failed? %>
64
- <li><pre class="terminal"><code><%=ansi_color_codes h(quantum.last_build.output) %></code></pre></li>
48
+ <% if ! quantum.active_builds.empty?%>
49
+ <% for @build in quantum.active_builds %>
50
+ <ul><%= erb(:build, {}, :quantum => quantum, :build => @build) %></ul>
65
51
  <% end %>
66
52
  <% end %>
67
53
  </ul>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ciquantum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-05-22 00:00:00.000000000 Z
14
+ date: 2012-05-31 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -132,7 +132,7 @@ dependencies:
132
132
  requirements:
133
133
  - - ! '>='
134
134
  - !ruby/object:Gem::Version
135
- version: 0.0.24
135
+ version: 0.0.25
136
136
  type: :runtime
137
137
  prerelease: false
138
138
  version_requirements: !ruby/object:Gem::Requirement
@@ -140,7 +140,7 @@ dependencies:
140
140
  requirements:
141
141
  - - ! '>='
142
142
  - !ruby/object:Gem::Version
143
- version: 0.0.24
143
+ version: 0.0.25
144
144
  - !ruby/object:Gem::Dependency
145
145
  name: rack-test
146
146
  requirement: !ruby/object:Gem::Requirement
@@ -197,6 +197,7 @@ files:
197
197
  - lib/ciquantum/commit.rb
198
198
  - lib/ciquantum/config.rb
199
199
  - lib/ciquantum/core.rb
200
+ - lib/ciquantum/public/javascript.js
200
201
  - lib/ciquantum/public/screen.css
201
202
  - lib/ciquantum/queue.rb
202
203
  - lib/ciquantum/server.rb
@@ -205,8 +206,8 @@ files:
205
206
  - lib/ciquantum/utils/coverage_merger.rb
206
207
  - lib/ciquantum/utils/mailer.rb
207
208
  - lib/ciquantum/version.rb
209
+ - lib/ciquantum/views/build.erb
208
210
  - lib/ciquantum/views/json.erb
209
- - lib/ciquantum/views/mail.erb
210
211
  - lib/ciquantum/views/mailer/html.erb
211
212
  - lib/ciquantum/views/mailer/text.erb
212
213
  - lib/ciquantum/views/template.erb
@@ -1,48 +0,0 @@
1
- <head>
2
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
3
- <title>[<%= @project %>] CIServer: state on branch <%= @build.branch %></title>
4
- <style type="text/css">
5
-
6
- .title {
7
- font-size: 120%;
8
- font-family: Verdana, Arial, Helvetica, sans-serif;
9
- border: 1px solid black;
10
- margin: 10px 20px;
11
- padding: 20px 10px;
12
- }
13
-
14
- .failed {
15
- background-color: #CC0000;
16
- }
17
-
18
- .worked {
19
- background-color: #00CC00;
20
- }
21
-
22
- pre {
23
- border: 1px solid black;
24
- background-color: #E0E0E0;
25
- }
26
-
27
- </style>
28
- </head>
29
- <body>
30
- <div class="title <%= @build.status.to_s %>"><%= @caption %></div><br>
31
- <div class="text">
32
- Last build <%= @project %> on branch <%= @build.branch %> <%= @build.status.to_s %>."<br><br>
33
-
34
- Details: <%= @build.commit.url %><br>
35
- Author: <%= @build.commit.author %><br>
36
- Message: <%= @build.commit.message %><br>
37
- </div>
38
- <% if @build.status == :failed %>
39
- <br>
40
- <code>
41
- <pre>
42
- Output:<br>
43
- <%= @build.clean_output %>
44
- </pre>
45
- </code>
46
- <% end %>
47
- <br><br><br>
48
- </body>