cijoe 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +12 -0
- data/Rakefile +1 -0
- data/bin/cijoe +5 -2
- data/examples/build-failed +22 -0
- data/examples/build-worked +22 -0
- data/lib/cijoe/build.rb +14 -1
- data/lib/cijoe/config.rb +9 -8
- data/lib/cijoe/public/screen.css +3 -2
- data/lib/cijoe/server.rb +14 -4
- data/lib/cijoe/version.rb +1 -1
- data/lib/cijoe/views/template.erb +6 -1
- data/lib/cijoe.rb +32 -4
- data/test/helper.rb +3 -0
- data/test/test_cijoe_server.rb +50 -0
- metadata +16 -2
data/README.markdown
CHANGED
@@ -83,6 +83,18 @@ Or do it the old fashion way:
|
|
83
83
|
etc.
|
84
84
|
|
85
85
|
|
86
|
+
Checkin' Status
|
87
|
+
---------------
|
88
|
+
|
89
|
+
Want to see how your build's doing without any of this fancy UI crap?
|
90
|
+
Ping Joe for the lowdown:
|
91
|
+
|
92
|
+
curl http://localhost:4567/ping
|
93
|
+
|
94
|
+
Joe will return `200 OK` if all is quiet on the Western Front. If
|
95
|
+
Joe's busy building or your last build failed, you'll get `412
|
96
|
+
PRECONDITION FAILED`.
|
97
|
+
|
86
98
|
Multiple Projects
|
87
99
|
-----------------
|
88
100
|
|
data/Rakefile
CHANGED
data/bin/cijoe
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
3
3
|
|
4
|
-
require 'cijoe'
|
5
4
|
require 'choice'
|
6
5
|
|
7
6
|
Choice.options do
|
@@ -46,4 +45,8 @@ Choice.options do
|
|
46
45
|
end
|
47
46
|
|
48
47
|
options = Choice.choices
|
49
|
-
|
48
|
+
$project_path = File.expand_path(Choice.rest[0])
|
49
|
+
|
50
|
+
require 'cijoe'
|
51
|
+
|
52
|
+
CIJoe::Server.start(options[:host], options[:port], $project_path)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
# Put this file to $PROJECT/.git/hooks/ for email notifications.
|
4
|
+
#
|
5
|
+
# You should have mail command provided by mailutils package on Debian
|
6
|
+
# based systems.
|
7
|
+
#
|
8
|
+
# sudo apt-get install mailutils
|
9
|
+
#
|
10
|
+
# You should have mail server running
|
11
|
+
#
|
12
|
+
# Do not forget: chmod +x build-failed
|
13
|
+
#
|
14
|
+
echo "
|
15
|
+
Visit http://ci.example.org/ for details
|
16
|
+
|
17
|
+
Author: $AUTHOR
|
18
|
+
Message:
|
19
|
+
$MESSAGE
|
20
|
+
|
21
|
+
$OUTPUT
|
22
|
+
" | mail -s "[example.org] BUILD FAILED $SHA" --to first@gmail.com second@gmail.com
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
# Put this file to $PROJECT/.git/hooks/ for email notifications.
|
4
|
+
#
|
5
|
+
# You should have mail command provided by mailutils package on Debian
|
6
|
+
# based systems.
|
7
|
+
#
|
8
|
+
# sudo apt-get install mailutils
|
9
|
+
#
|
10
|
+
# You should have mail server running
|
11
|
+
#
|
12
|
+
# Do not forget: chmod +x build-worked
|
13
|
+
#
|
14
|
+
echo "
|
15
|
+
Visit http://ci.example.org/ for details
|
16
|
+
|
17
|
+
Author: $AUTHOR
|
18
|
+
Message:
|
19
|
+
$MESSAGE
|
20
|
+
|
21
|
+
" | mail -s "[example.org] build OK" --to first@gmail.com second@gmail.com
|
22
|
+
|
data/lib/cijoe/build.rb
CHANGED
@@ -20,8 +20,21 @@ class CIJoe
|
|
20
20
|
status == :worked
|
21
21
|
end
|
22
22
|
|
23
|
+
def building?
|
24
|
+
status == :building
|
25
|
+
end
|
26
|
+
|
27
|
+
def duration
|
28
|
+
return if building?
|
29
|
+
finished_at - started_at
|
30
|
+
end
|
31
|
+
|
23
32
|
def short_sha
|
24
|
-
|
33
|
+
if sha
|
34
|
+
sha[0,7]
|
35
|
+
else
|
36
|
+
"<unknown>"
|
37
|
+
end
|
25
38
|
end
|
26
39
|
|
27
40
|
def clean_output
|
data/lib/cijoe/config.rb
CHANGED
@@ -5,8 +5,9 @@ class CIJoe
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def initialize(command, parent = nil)
|
8
|
-
@command
|
9
|
-
@parent
|
8
|
+
@command = command
|
9
|
+
@parent = parent
|
10
|
+
@project_path = $project_path || File.join(File.dirname(__FILE__), '../../')
|
10
11
|
end
|
11
12
|
|
12
13
|
def method_missing(command, *args)
|
@@ -14,10 +15,10 @@ class CIJoe
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def to_s
|
17
|
-
git_command = "git config #{config_string}"
|
18
|
+
git_command = "cd #{@project_path} && git config #{config_string}"
|
18
19
|
result = `#{git_command} 2>&1`.chomp
|
19
20
|
process_status = $?
|
20
|
-
|
21
|
+
|
21
22
|
if successful_command?(process_status) || config_command_with_empty_value?(result,process_status)
|
22
23
|
return result
|
23
24
|
else
|
@@ -28,15 +29,15 @@ class CIJoe
|
|
28
29
|
def config_string
|
29
30
|
@parent ? "#{@parent.config_string}.#{@command}" : @command
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
private
|
33
|
-
|
34
|
+
|
34
35
|
def successful_command?(process_status)
|
35
36
|
process_status.exitstatus.to_i == 0
|
36
37
|
end
|
37
|
-
|
38
|
+
|
38
39
|
def config_command_with_empty_value?(result, process_status)
|
39
40
|
process_status.exitstatus.to_i == 1 && result.empty?
|
40
|
-
end
|
41
|
+
end
|
41
42
|
end
|
42
43
|
end
|
data/lib/cijoe/public/screen.css
CHANGED
@@ -83,7 +83,8 @@ ul.posts {
|
|
83
83
|
line-height: 1.75em;
|
84
84
|
}
|
85
85
|
|
86
|
-
ul.posts .date
|
86
|
+
ul.posts .date,
|
87
|
+
ul.posts .duration {
|
87
88
|
color: #aaa;
|
88
89
|
font-family: Monaco, "Courier New", monospace;
|
89
90
|
font-size: 80%;
|
@@ -98,7 +99,7 @@ ul.posts {
|
|
98
99
|
.site {
|
99
100
|
font-size: 110%;
|
100
101
|
text-align: justify;
|
101
|
-
width:
|
102
|
+
width: 80%;
|
102
103
|
margin: 3em auto 2em auto;
|
103
104
|
line-height: 1.5em;
|
104
105
|
}
|
data/lib/cijoe/server.rb
CHANGED
@@ -3,6 +3,8 @@ require 'erb'
|
|
3
3
|
|
4
4
|
class CIJoe
|
5
5
|
class Server < Sinatra::Base
|
6
|
+
attr_reader :joe
|
7
|
+
|
6
8
|
dir = File.dirname(File.expand_path(__FILE__))
|
7
9
|
|
8
10
|
set :views, "#{dir}/views"
|
@@ -10,16 +12,24 @@ class CIJoe
|
|
10
12
|
set :static, true
|
11
13
|
set :lock, true
|
12
14
|
|
13
|
-
before {
|
15
|
+
before { joe.restore }
|
16
|
+
|
17
|
+
get '/ping' do
|
18
|
+
if joe.building? || !joe.last_build || !joe.last_build.worked?
|
19
|
+
halt 412, joe.last_build ? joe.last_build.sha : "building"
|
20
|
+
end
|
21
|
+
|
22
|
+
joe.last_build.sha
|
23
|
+
end
|
14
24
|
|
15
25
|
get '/?' do
|
16
|
-
erb(:template, {}, :joe =>
|
26
|
+
erb(:template, {}, :joe => joe)
|
17
27
|
end
|
18
28
|
|
19
29
|
post '/?' do
|
20
30
|
payload = params[:payload].to_s
|
21
|
-
if payload.empty? || payload.include?(
|
22
|
-
|
31
|
+
if payload.empty? || payload.include?(joe.git_branch)
|
32
|
+
joe.build
|
23
33
|
end
|
24
34
|
redirect request.path
|
25
35
|
end
|
data/lib/cijoe/version.rb
CHANGED
@@ -29,7 +29,12 @@
|
|
29
29
|
<% end %>
|
30
30
|
|
31
31
|
<% if joe.last_build %>
|
32
|
-
<li
|
32
|
+
<li>
|
33
|
+
<span class="date"><%= pretty_time(joe.last_build.finished_at) %></span> » Built <a href="<%= joe.url %>/commits/<%= joe.last_build.sha %>"><%= joe.last_build.short_sha %></a> <span class="<%= joe.last_build.status %>">(<%= joe.last_build.status %>)</span>
|
34
|
+
<% if joe.last_build.duration %>
|
35
|
+
in <span class="duration"><%= joe.last_build.duration %></span> seconds.
|
36
|
+
<% end %>
|
37
|
+
</li>
|
33
38
|
<% if joe.last_build.failed? %>
|
34
39
|
<li><pre class="terminal"><code><%=ansi_color_codes h(joe.last_build.output) %></code></pre></li>
|
35
40
|
<% end %>
|
data/lib/cijoe.rb
CHANGED
@@ -68,6 +68,7 @@ class CIJoe
|
|
68
68
|
@current_build.status = status
|
69
69
|
@current_build.output = output
|
70
70
|
@last_build = @current_build
|
71
|
+
|
71
72
|
@current_build = nil
|
72
73
|
write_build 'current', @current_build
|
73
74
|
write_build 'last', @last_build
|
@@ -83,6 +84,20 @@ class CIJoe
|
|
83
84
|
Thread.new { build! }
|
84
85
|
end
|
85
86
|
|
87
|
+
def open_pipe(cmd)
|
88
|
+
read, write = IO.pipe
|
89
|
+
|
90
|
+
pid = fork do
|
91
|
+
read.close
|
92
|
+
$stdout.reopen write
|
93
|
+
exec cmd
|
94
|
+
end
|
95
|
+
|
96
|
+
write.close
|
97
|
+
|
98
|
+
yield read, pid
|
99
|
+
end
|
100
|
+
|
86
101
|
# update git then run the build
|
87
102
|
def build!
|
88
103
|
build = @current_build
|
@@ -91,14 +106,21 @@ class CIJoe
|
|
91
106
|
build.sha = git_sha
|
92
107
|
write_build 'current', build
|
93
108
|
|
94
|
-
|
109
|
+
open_pipe("#{runner_command} 2>&1") do |pipe, pid|
|
110
|
+
puts "#{Time.now.to_i}: Building #{build.short_sha}: pid=#{pid}"
|
111
|
+
|
95
112
|
build.pid = pid
|
96
113
|
write_build 'current', build
|
97
114
|
output = pipe.read
|
98
115
|
end
|
99
116
|
|
100
|
-
|
117
|
+
Process.waitpid(build.pid)
|
118
|
+
status = $?.exitstatus.to_i
|
119
|
+
puts "#{Time.now.to_i}: Built #{build.short_sha}: status=#{status}"
|
120
|
+
|
121
|
+
status == 0 ? build_worked(output) : build_failed('', output)
|
101
122
|
rescue Object => e
|
123
|
+
puts "Exception building: #{e.message} (#{e.class})"
|
102
124
|
build_failed('', e.to_s)
|
103
125
|
end
|
104
126
|
|
@@ -147,8 +169,14 @@ class CIJoe
|
|
147
169
|
|
148
170
|
# restore current / last build state from disk.
|
149
171
|
def restore
|
150
|
-
@last_build
|
151
|
-
|
172
|
+
unless @last_build
|
173
|
+
@last_build = read_build('last')
|
174
|
+
end
|
175
|
+
|
176
|
+
unless @current_build
|
177
|
+
@current_build = read_build('current')
|
178
|
+
end
|
179
|
+
|
152
180
|
Process.kill(0, @current_build.pid) if @current_build && @current_build.pid
|
153
181
|
rescue Errno::ESRCH
|
154
182
|
# build pid isn't running anymore. assume previous
|
data/test/helper.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "rack/test"
|
3
|
+
require "cijoe/server"
|
4
|
+
|
5
|
+
class TestCIJoeServer < Test::Unit::TestCase
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
class ::CIJoe
|
9
|
+
attr_writer :current_build, :last_build
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :app
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@app = CIJoe::Server.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_ping
|
19
|
+
app.joe.last_build = build :worked
|
20
|
+
assert !app.joe.building?, "have a last build, but not a current"
|
21
|
+
|
22
|
+
get "/ping"
|
23
|
+
assert_equal 200, last_response.status
|
24
|
+
assert_equal app.joe.last_build.sha, last_response.body
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_ping_building
|
28
|
+
app.joe.current_build = build :building
|
29
|
+
assert app.joe.building?, "buildin' a awsum project"
|
30
|
+
|
31
|
+
get "/ping"
|
32
|
+
assert_equal 412, last_response.status
|
33
|
+
assert_equal "building", last_response.body
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_ping_failed
|
37
|
+
app.joe.last_build = build :failed
|
38
|
+
|
39
|
+
get "/ping"
|
40
|
+
assert_equal 412, last_response.status
|
41
|
+
assert_equal app.joe.last_build.sha, last_response.body
|
42
|
+
end
|
43
|
+
|
44
|
+
# Create a new, fake build. All we care about is status.
|
45
|
+
|
46
|
+
def build status
|
47
|
+
CIJoe::Build.new "user", "project", Time.now, Time.now,
|
48
|
+
"deadbeef", status, "output", 1337
|
49
|
+
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cijoe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wanstrath
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-28 00:00:00 -08:00
|
13
13
|
default_executable: cijoe
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,6 +32,16 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: "0"
|
34
34
|
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rack-test
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
35
45
|
description: CI Joe is a simple Continuous Integration server.
|
36
46
|
email: chris@ozmm.org
|
37
47
|
executables:
|
@@ -48,6 +58,8 @@ files:
|
|
48
58
|
- Rakefile
|
49
59
|
- bin/cijoe
|
50
60
|
- deps.rip
|
61
|
+
- examples/build-failed
|
62
|
+
- examples/build-worked
|
51
63
|
- examples/cijoe.ru
|
52
64
|
- examples/cijoed
|
53
65
|
- lib/cijoe.rb
|
@@ -63,6 +75,7 @@ files:
|
|
63
75
|
- lib/cijoe/views/template.erb
|
64
76
|
- test/helper.rb
|
65
77
|
- test/test_cijoe.rb
|
78
|
+
- test/test_cijoe_server.rb
|
66
79
|
has_rdoc: true
|
67
80
|
homepage: http://github.com/defunkt/cijoe
|
68
81
|
licenses: []
|
@@ -94,3 +107,4 @@ summary: CI Joe is a simple Continuous Integration server.
|
|
94
107
|
test_files:
|
95
108
|
- test/helper.rb
|
96
109
|
- test/test_cijoe.rb
|
110
|
+
- test/test_cijoe_server.rb
|