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 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
@@ -16,6 +16,7 @@ begin
16
16
  gemspec.authors = ["Chris Wanstrath"]
17
17
  gemspec.add_dependency 'choice'
18
18
  gemspec.add_dependency 'sinatra'
19
+ gemspec.add_development_dependency 'rack-test'
19
20
  gemspec.version = CIJoe::Version.to_s
20
21
  end
21
22
  rescue LoadError
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
- CIJoe::Server.start(options[:host], options[:port], Choice.rest[0])
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
- sha[0,7] if sha
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 = command
9
- @parent = 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
@@ -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: 40em;
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 { @joe.restore }
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 => @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?(@joe.git_branch)
22
- @joe.build
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
@@ -1,3 +1,3 @@
1
1
  class CIJoe
2
- Version = "0.2.0"
2
+ Version = "0.3.0"
3
3
  end
@@ -29,7 +29,12 @@
29
29
  <% end %>
30
30
 
31
31
  <% if joe.last_build %>
32
- <li><span class="date"><%= pretty_time(joe.last_build.finished_at) %></span> &raquo; 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></li>
32
+ <li>
33
+ <span class="date"><%= pretty_time(joe.last_build.finished_at) %></span> &raquo; 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
- IO.popen("#{runner_command} 2>&1") do |pipe|
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
- $?.exitstatus.to_i == 0 ? build_worked(output) : build_failed('', output)
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 = read_build('last')
151
- @current_build = read_build('current')
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
@@ -5,5 +5,8 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
6
  require 'cijoe'
7
7
 
8
+ CIJoe::Server.set :project_path, "."
9
+ CIJoe::Server.set :environment, "test"
10
+
8
11
  class Test::Unit::TestCase
9
12
  end
@@ -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.2.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: 2009-12-24 00:00:00 -08:00
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