cijoe 0.2.0 → 0.3.0

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/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