cijoe 0.9.1 → 0.9.2

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.md CHANGED
@@ -49,6 +49,9 @@ put whatever you want in there.
49
49
  Tip: your repo's `HEAD` will point to the commit used to run the
50
50
  build. Pull any metadata you want out of that scro.
51
51
 
52
+ ** WARNING ** Do not run this against a git repo that has unpushed
53
+ commits, as this will do a hard reset against the github remote and
54
+ wipe out unpushed changes.
52
55
 
53
56
  Other Branches
54
57
  ----------------------
@@ -77,8 +80,7 @@ Campfire notification is included, because it's what we use. Want Joe
77
80
  notify your Campfire? Put this in your repo's `.git/config`:
78
81
 
79
82
  [campfire]
80
- user = your@campfire.email
81
- pass = passw0rd
83
+ token = abcd1234
82
84
  subdomain = whatever
83
85
  room = Awesomeness
84
86
  ssl = false
@@ -86,7 +88,7 @@ notify your Campfire? Put this in your repo's `.git/config`:
86
88
  Or do it the old fashion way:
87
89
 
88
90
  $ cd yourrepo
89
- $ git config --add campfire.user chris@ozmm.org
91
+ $ git config --add campfire.token abcd1234
90
92
  $ git config --add campfire.subdomain github
91
93
  etc.
92
94
 
@@ -147,6 +149,7 @@ Other CI Servers
147
149
 
148
150
  Need more features? More notifiers? Check out one of these bad boys:
149
151
 
152
+ * [Jenkins](http://jenkins-ci.org/)
150
153
  * [Cerberus](http://cerberus.rubyforge.org/)
151
154
  * [Integrity](http://integrityapp.com/)
152
155
  * [CruiseControl.rb](http://cruisecontrolrb.thoughtworks.com/)
@@ -154,6 +157,12 @@ Need more features? More notifiers? Check out one of these bad boys:
154
157
  * [Signal](http://www.github.com/dcrec1/signal)
155
158
 
156
159
 
160
+ Does GitHub use cijoe?
161
+ ---------------------------------
162
+
163
+ No. We use [Jenkins](http://jenkins-ci.org/).
164
+
165
+
157
166
  Screenshots
158
167
  ------------------
159
168
 
@@ -165,7 +174,4 @@ Screenshots
165
174
  Questions? Concerns?
166
175
  ---------------------------------
167
176
 
168
- [Issues](http://github.com/defunkt/cijoe/issues) or [the mailing list](http://groups.google.com/group/cijoe).
169
-
170
-
171
- ( Chris Wanstrath :: chris@ozmm.org )
177
+ [Issues](http://github.com/defunkt/cijoe/issues)
@@ -21,7 +21,7 @@ require 'cijoe/campfire'
21
21
  require 'cijoe/server'
22
22
 
23
23
  class CIJoe
24
- attr_reader :user, :project, :url, :current_build, :last_build
24
+ attr_reader :user, :project, :url, :current_build, :last_build, :campfire
25
25
 
26
26
  def initialize(project_path)
27
27
  @project_path = File.expand_path(project_path)
@@ -29,6 +29,8 @@ class CIJoe
29
29
  @user, @project = git_user_and_project
30
30
  @url = "http://github.com/#{@user}/#{@project}"
31
31
 
32
+ @campfire = CIJoe::Campfire.new(project_path)
33
+
32
34
  @last_build = nil
33
35
  @current_build = nil
34
36
 
@@ -77,7 +79,7 @@ class CIJoe
77
79
  @current_build = nil
78
80
  write_build 'current', @current_build
79
81
  write_build 'last', @last_build
80
- @last_build.notify if @last_build.respond_to? :notify
82
+ @campfire.notify(@last_build) if @campfire.valid?
81
83
 
82
84
  # another build waits
83
85
  if !repo_config.buildallfile.to_s.empty? && File.exist?(repo_config.buildallfile.to_s)
@@ -1,30 +1,26 @@
1
1
  class CIJoe
2
- module Campfire
3
- def self.activate(project_path)
2
+ class Campfire
3
+ attr_reader :project_path, :build
4
+
5
+ def initialize(project_path)
4
6
  @project_path = project_path
5
-
6
- if valid_config?
7
+ if valid?
7
8
  require 'tinder'
8
-
9
- CIJoe::Build.class_eval do
10
- include CIJoe::Campfire
11
- end
12
-
13
- puts "Loaded Campfire notifier"
9
+ puts "Loaded Campfire notifier for #{project_path}."
14
10
  elsif ENV['RACK_ENV'] != 'test'
15
- puts "Can't load Campfire notifier."
11
+ puts "Can't load Campfire notifier for #{project_path}."
16
12
  puts "Please add the following to your project's .git/config:"
17
13
  puts "[campfire]"
18
- puts "\ttoken = your_api_token"
14
+ puts "\ttoken = abcd1234"
19
15
  puts "\tsubdomain = whatever"
20
16
  puts "\troom = Awesomeness"
21
17
  puts "\tssl = false"
22
18
  end
23
19
  end
24
-
25
- def self.config
26
- campfire_config = Config.new('campfire', @project_path)
27
- @config ||= {
20
+
21
+ def campfire_config
22
+ campfire_config = Config.new('campfire', project_path)
23
+ @config = {
28
24
  :subdomain => campfire_config.subdomain.to_s,
29
25
  :token => campfire_config.token.to_s,
30
26
  :room => campfire_config.room.to_s,
@@ -32,22 +28,27 @@ class CIJoe
32
28
  }
33
29
  end
34
30
 
35
- def self.valid_config?
31
+ def valid?
36
32
  %w( subdomain token room ).all? do |key|
37
- !config[key.intern].empty?
33
+ !campfire_config[key.intern].empty?
38
34
  end
39
35
  end
40
36
 
41
- def notify
42
- room.speak "#{short_message}. #{commit.url}"
43
- room.paste full_message if failed?
44
- room.leave
37
+ def notify(build)
38
+ begin
39
+ @build = build
40
+ room.speak "#{short_message}. #{build.commit.url}"
41
+ room.paste full_message if build.failed?
42
+ room.leave
43
+ rescue
44
+ puts "Please check your campfire config for #{project_path}."
45
+ end
45
46
  end
46
47
 
47
48
  private
48
49
  def room
49
50
  @room ||= begin
50
- config = Campfire.config
51
+ config = campfire_config
51
52
  campfire = Tinder::Campfire.new(config[:subdomain],
52
53
  :token => config[:token],
53
54
  :ssl => config[:ssl] || false)
@@ -56,17 +57,17 @@ class CIJoe
56
57
  end
57
58
 
58
59
  def short_message
59
- "#{branch} at #{short_sha} of #{project} " +
60
- (worked? ? "passed" : "failed") + " (#{duration.to_i}s)"
60
+ "#{build.branch} at #{build.short_sha} of #{build.project} " +
61
+ (build.worked? ? "passed" : "failed") + " (#{build.duration.to_i}s)"
61
62
  end
62
63
 
63
64
  def full_message
64
65
  <<-EOM
65
- Commit Message: #{commit.message}
66
- Commit Date: #{commit.committed_at}
67
- Commit Author: #{commit.author}
66
+ Commit Message: #{build.commit.message}
67
+ Commit Date: #{build.commit.committed_at}
68
+ Commit Author: #{build.commit.author}
68
69
 
69
- #{clean_output}
70
+ #{build.clean_output}
70
71
  EOM
71
72
  end
72
73
  end
@@ -1,5 +1,6 @@
1
1
  require 'sinatra/base'
2
2
  require 'erb'
3
+ require 'json'
3
4
 
4
5
  class CIJoe
5
6
  class Server < Sinatra::Base
@@ -27,15 +28,15 @@ class CIJoe
27
28
  end
28
29
 
29
30
  post '/?' do
30
- payload = params[:payload].to_s
31
- if payload =~ /"ref":"(.+?)"/
32
- pushed_branch = $1.split('/').last
31
+ unless params[:rebuild]
32
+ payload = JSON.parse(params[:payload])
33
+ pushed_branch = payload["ref"].split('/').last
33
34
  end
34
-
35
- # Only build if we were given an explicit branch via `?branch=blah`,
36
- # no payload exists (we're probably testing), or the payload exists and
37
- # the "ref" property matches our specified build branch.
38
- if params[:branch] || payload.empty? || pushed_branch == joe.git_branch
35
+
36
+ # Only build if we were given an explicit branch via `?branch=blah`
37
+ # or the payload exists and the "ref" property matches our
38
+ # specified build branch.
39
+ if params[:branch] || params[:rebuild] || pushed_branch == joe.git_branch
39
40
  joe.build(params[:branch])
40
41
  end
41
42
 
@@ -79,8 +80,6 @@ class CIJoe
79
80
  super
80
81
  check_project
81
82
  @joe = CIJoe.new(options.project_path)
82
-
83
- CIJoe::Campfire.activate(options.project_path)
84
83
  end
85
84
 
86
85
  def self.start(host, port, project_path)
@@ -1,3 +1,3 @@
1
1
  class CIJoe
2
- Version = VERSION = "0.9.1"
2
+ Version = VERSION = "0.9.2"
3
3
  end
@@ -2,7 +2,15 @@
2
2
  <% if joe.last_build %>
3
3
  {"name":"<%= joe.project %>",
4
4
  "url":"<%= joe.url %>",
5
- "color":"<%= joe.last_build.status.to_s == "failed" ? 'red' : 'blue' %>"
5
+ "color":"<%= joe.last_build.status.to_s == "failed" ? 'red' : 'blue' %>",
6
+ "status":"<%= joe.last_build.status %>",
7
+ "started_at":"<%= pretty_time(joe.last_build.started_at) %>",
8
+ "finished_at":"<%= pretty_time(joe.last_build.finished_at) %>",
9
+ "duration":"<%= joe.last_build.duration if joe.last_build.duration %>",
10
+ "sha":"<%= joe.last_build.sha %>",
11
+ "short_sha":"<%= joe.last_build.short_sha %>",
12
+ "commit_url":"<%= joe.last_build.commit.url if joe.last_build.commit %>",
13
+ "branch":"<%= joe.last_build.branch %>"
6
14
  }
7
15
  <% end %>
8
16
  ]}
@@ -25,7 +25,7 @@
25
25
  <% end %>
26
26
  </li>
27
27
  <% else %>
28
- <li><form method="POST"><input type="submit" value="Build"/></form></li>
28
+ <li><form method="POST"><input type="hidden", name="rebuild" value="true"><input type="submit" value="Build"/></form></li>
29
29
  <% end %>
30
30
 
31
31
  <% if joe.last_build %>
@@ -0,0 +1,52 @@
1
+ {
2
+ "after": "416cb2f7105e7f989bc223d1a975b93a6491b276",
3
+ "before": "0ae4da1eea2d191b33ebfbd5db48e3c1f91953ad",
4
+ "commits": [
5
+ {
6
+ "added": [
7
+
8
+ ],
9
+ "author": {
10
+ "email": "joshua.owens@gmail.com",
11
+ "name": "Josh Owens",
12
+ "username": "queso"
13
+ },
14
+ "id": "09293a1703b3bdb36aba70d38abd5e44396c50a5",
15
+ "message": "Update README",
16
+ "modified": [
17
+ "README.textile"
18
+ ],
19
+ "removed": [
20
+
21
+ ],
22
+ "timestamp": "2011-02-07T15:27:35-08:00",
23
+ "url": "https:\/\/github.com\/fourbeansoup\/broth\/commit\/09293a1703b3bdb36aba70d38abd5e44396c50a5"
24
+ }
25
+ ],
26
+ "compare": "https:\/\/github.com\/fourbeansoup\/broth\/compare\/0ae4da1...416cb2f",
27
+ "forced": false,
28
+ "ref": "refs\/heads\/master",
29
+ "repository": {
30
+ "created_at": "2009\/12\/05 10:44:57 -0800",
31
+ "description": "FourBeanSoup's Broth Application, a tasty starting point for every app",
32
+ "fork": true,
33
+ "forks": 4,
34
+ "has_downloads": true,
35
+ "has_issues": true,
36
+ "has_wiki": true,
37
+ "homepage": "",
38
+ "language": "JavaScript",
39
+ "name": "broth",
40
+ "open_issues": 2,
41
+ "organization": "fourbeansoup",
42
+ "owner": {
43
+ "email": "josh+scm@fourbeansoup.com",
44
+ "name": "fourbeansoup"
45
+ },
46
+ "private": false,
47
+ "pushed_at": "2011\/02\/07 17:17:00 -0800",
48
+ "size": 604,
49
+ "url": "https:\/\/github.com\/fourbeansoup\/broth",
50
+ "watchers": 10
51
+ }
52
+ }
@@ -10,5 +10,37 @@ require 'cijoe'
10
10
  CIJoe::Server.set :project_path, "."
11
11
  CIJoe::Server.set :environment, "test"
12
12
 
13
+ TMP_DIR = '/tmp/cijoe_test'
14
+
15
+ def tmp_dir
16
+ TMP_DIR
17
+ end
18
+
19
+ def setup_git_info(options = {})
20
+ @tmp_dirs ||= []
21
+ @tmp_dirs += [options[:tmp_dir]]
22
+ create_tmpdir!(options[:tmp_dir])
23
+ dir = options[:tmp_dir] || tmp_dir
24
+ `cd #{dir} && git init`
25
+ options[:config].each do |key, value|
26
+ `cd #{dir} && git config --add #{key} "#{value}"`
27
+ end
28
+ end
29
+
30
+ def teardown_git_info
31
+ remove_tmpdir!
32
+ @tmp_dirs.each do |dir|
33
+ remove_tmpdir!(dir)
34
+ end
35
+ end
36
+
37
+ def remove_tmpdir!(passed_dir = nil)
38
+ FileUtils.rm_rf(passed_dir || tmp_dir)
39
+ end
40
+
41
+ def create_tmpdir!(passed_dir = nil)
42
+ FileUtils.mkdir_p(passed_dir || tmp_dir)
43
+ end
44
+
13
45
  class Test::Unit::TestCase
14
46
  end
@@ -0,0 +1,48 @@
1
+ require "helper"
2
+ require "cijoe"
3
+ require "fakefs/safe"
4
+
5
+
6
+ class TestCampfire < Test::Unit::TestCase
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
+ joe = @app.joe
17
+
18
+ # make Build#restore a no-op so we don't overwrite our current/last
19
+ # build attributes set from tests.
20
+ def joe.restore
21
+ end
22
+
23
+ # make CIJoe#build! and CIJoe#git_update a no-op so we don't overwrite our local changes
24
+ # or local commits nor should we run tests.
25
+ def joe.build!
26
+ end
27
+ end
28
+
29
+ def teardown
30
+ teardown_git_info
31
+ end
32
+
33
+ def test_campfire_pulls_campfire_config_from_git_config
34
+ setup_git_info(:config => {"campfire.subdomain" => "github", "remote.origin.url" => "https://github.com/defunkt/cijoe.git"})
35
+ cf = CIJoe::Campfire.new(tmp_dir)
36
+ assert_equal "github", cf.campfire_config[:subdomain]
37
+ end
38
+
39
+ def test_campfire_pulls_campfire_config_from_its_own_git_config
40
+ setup_git_info(:config => {"campfire.subdomain" => "github"})
41
+ setup_git_info(:config => {"campfire.subdomain" => "37signals"}, :tmp_dir => "/tmp/cijoe_test_37signals")
42
+ cf1 = CIJoe::Campfire.new(tmp_dir)
43
+ cf2 = CIJoe::Campfire.new("/tmp/cijoe_test_37signals")
44
+ assert_equal "github", cf1.campfire_config[:subdomain]
45
+ assert_equal "37signals", cf2.campfire_config[:subdomain]
46
+ end
47
+
48
+ end
@@ -13,11 +13,17 @@ class TestCIJoeServer < Test::Unit::TestCase
13
13
 
14
14
  def setup
15
15
  @app = CIJoe::Server.new
16
+ joe = @app.joe
17
+
16
18
  # make Build#restore a no-op so we don't overwrite our current/last
17
19
  # build attributes set from tests.
18
- joe = @app.joe
19
20
  def joe.restore
20
21
  end
22
+
23
+ # make CIJoe#build! and CIJoe#git_update a no-op so we don't overwrite our local changes
24
+ # or local commits nor should we run tests.
25
+ def joe.build!
26
+ end
21
27
  end
22
28
 
23
29
  def test_ping
@@ -64,6 +70,30 @@ class TestCIJoeServer < Test::Unit::TestCase
64
70
  assert_equal current_build, app.joe.current_build
65
71
  end
66
72
 
73
+ def test_post_with_json_works
74
+ post '/', :payload => File.read("#{Dir.pwd}/test/fixtures/payload.json")
75
+ assert app.joe.building?
76
+ assert_equal 302, last_response.status
77
+ end
78
+
79
+ def test_post_does_not_build_on_branch_mismatch
80
+ post "/", :payload => {"ref" => "refs/heads/dont_build"}.to_json
81
+ assert !app.joe.building?
82
+ assert_equal 302, last_response.status
83
+ end
84
+
85
+ def test_post_does_build_on_branch_match
86
+ post "/", :payload => {"ref" => "refs/heads/master"}.to_json
87
+ assert app.joe.building?
88
+ assert_equal 302, last_response.status
89
+ end
90
+
91
+ def test_post_does_build_when_build_button_is_used
92
+ post "/", :rebuild => true
93
+ assert app.joe.building?
94
+ assert_equal 302, last_response.status
95
+ end
96
+
67
97
  def test_jsonp_should_return_plain_json_without_param
68
98
  app.joe.last_build = build :failed
69
99
  get "/api/json"
@@ -74,7 +104,6 @@ class TestCIJoeServer < Test::Unit::TestCase
74
104
  def test_jsonp_should_return_jsonp_with_param
75
105
  app.joe.last_build = build :failed
76
106
  get "/api/json?jsonp=fooberz"
77
- puts last_response.inspect
78
107
  assert_equal 200, last_response.status
79
108
  assert_equal 'application/json', last_response.content_type
80
109
  assert_match /^fooberz\(/, last_response.body
metadata CHANGED
@@ -1,21 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cijoe
3
3
  version: !ruby/object:Gem::Version
4
- hash: 57
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 9
9
- - 1
10
- version: 0.9.1
4
+ prerelease:
5
+ version: 0.9.2
11
6
  platform: ruby
12
7
  authors:
13
8
  - Chris Wanstrath
9
+ - Josh Owens
14
10
  autorequire:
15
11
  bindir: bin
16
12
  cert_chain: []
17
13
 
18
- date: 2011-02-08 00:00:00 -08:00
14
+ date: 2011-04-19 00:00:00 -04:00
19
15
  default_executable:
20
16
  dependencies:
21
17
  - !ruby/object:Gem::Dependency
@@ -26,9 +22,6 @@ dependencies:
26
22
  requirements:
27
23
  - - ">="
28
24
  - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
25
  version: "0"
33
26
  type: :runtime
34
27
  version_requirements: *id001
@@ -40,26 +33,42 @@ dependencies:
40
33
  requirements:
41
34
  - - ">="
42
35
  - !ruby/object:Gem::Version
43
- hash: 3
44
- segments:
45
- - 0
46
36
  version: "0"
47
37
  type: :runtime
48
38
  version_requirements: *id002
49
39
  - !ruby/object:Gem::Dependency
50
- name: rack-test
40
+ name: json
51
41
  prerelease: false
52
42
  requirement: &id003 !ruby/object:Gem::Requirement
53
43
  none: false
54
44
  requirements:
55
45
  - - ">="
56
46
  - !ruby/object:Gem::Version
57
- hash: 3
58
- segments:
59
- - 0
60
47
  version: "0"
61
- type: :development
48
+ type: :runtime
62
49
  version_requirements: *id003
50
+ - !ruby/object:Gem::Dependency
51
+ name: tinder
52
+ prerelease: false
53
+ requirement: &id004 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 1.4.0
59
+ type: :runtime
60
+ version_requirements: *id004
61
+ - !ruby/object:Gem::Dependency
62
+ name: rack-test
63
+ prerelease: false
64
+ requirement: &id005 !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id005
63
72
  description: " cijoe is a sinatra-based continuous integration server. It's like an\n old rusty pickup truck: it might be smelly and gross, but it gets the\n job done.\n"
64
73
  email: chris@ozmm.org
65
74
  executables:
@@ -85,7 +94,9 @@ files:
85
94
  - lib/cijoe/views/template.erb
86
95
  - lib/cijoe.rb
87
96
  - bin/cijoe
97
+ - test/fixtures/payload.json
88
98
  - test/helper.rb
99
+ - test/test_campfire.rb
89
100
  - test/test_cijoe.rb
90
101
  - test/test_cijoe_server.rb
91
102
  has_rdoc: true
@@ -102,23 +113,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
113
  requirements:
103
114
  - - ">="
104
115
  - !ruby/object:Gem::Version
105
- hash: 3
106
- segments:
107
- - 0
108
116
  version: "0"
109
117
  required_rubygems_version: !ruby/object:Gem::Requirement
110
118
  none: false
111
119
  requirements:
112
120
  - - ">="
113
121
  - !ruby/object:Gem::Version
114
- hash: 3
115
- segments:
116
- - 0
117
122
  version: "0"
118
123
  requirements: []
119
124
 
120
125
  rubyforge_project:
121
- rubygems_version: 1.3.7
126
+ rubygems_version: 1.6.2
122
127
  signing_key:
123
128
  specification_version: 3
124
129
  summary: cijoe builds your builds.