foca-integrity 0.1.8 → 0.1.9.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.
Files changed (75) hide show
  1. data/README.markdown +7 -0
  2. data/Rakefile +89 -81
  3. data/config/config.sample.ru +11 -21
  4. data/config/config.sample.yml +15 -12
  5. data/lib/integrity.rb +21 -23
  6. data/lib/integrity/app.rb +138 -0
  7. data/lib/integrity/author.rb +39 -0
  8. data/lib/integrity/build.rb +54 -31
  9. data/lib/integrity/commit.rb +71 -0
  10. data/lib/integrity/helpers.rb +3 -3
  11. data/lib/integrity/helpers/authorization.rb +2 -2
  12. data/lib/integrity/helpers/forms.rb +3 -3
  13. data/lib/integrity/helpers/pretty_output.rb +1 -1
  14. data/lib/integrity/helpers/rendering.rb +6 -1
  15. data/lib/integrity/helpers/resources.rb +9 -3
  16. data/lib/integrity/helpers/urls.rb +15 -13
  17. data/lib/integrity/installer.rb +43 -60
  18. data/lib/integrity/migrations.rb +31 -48
  19. data/lib/integrity/notifier.rb +14 -16
  20. data/lib/integrity/notifier/base.rb +29 -19
  21. data/lib/integrity/notifier/test_helpers.rb +100 -0
  22. data/lib/integrity/project.rb +69 -33
  23. data/lib/integrity/project_builder.rb +23 -14
  24. data/lib/integrity/scm/git.rb +15 -14
  25. data/lib/integrity/scm/git/uri.rb +9 -9
  26. data/test/acceptance/api_test.rb +97 -0
  27. data/test/acceptance/browse_project_builds_test.rb +65 -0
  28. data/test/acceptance/browse_project_test.rb +95 -0
  29. data/test/acceptance/build_notifications_test.rb +42 -0
  30. data/test/acceptance/create_project_test.rb +97 -0
  31. data/test/acceptance/delete_project_test.rb +53 -0
  32. data/test/acceptance/edit_project_test.rb +117 -0
  33. data/test/acceptance/error_page_test.rb +18 -0
  34. data/test/acceptance/helpers.rb +2 -0
  35. data/test/acceptance/installer_test.rb +62 -0
  36. data/test/acceptance/manual_build_project_test.rb +82 -0
  37. data/test/acceptance/notifier_test.rb +109 -0
  38. data/test/acceptance/project_syndication_test.rb +30 -0
  39. data/test/acceptance/stylesheet_test.rb +18 -0
  40. data/test/helpers.rb +59 -27
  41. data/test/helpers/acceptance.rb +19 -64
  42. data/test/helpers/acceptance/email_notifier.rb +55 -0
  43. data/test/helpers/acceptance/git_helper.rb +15 -15
  44. data/test/helpers/acceptance/textfile_notifier.rb +3 -3
  45. data/test/helpers/expectations.rb +0 -1
  46. data/test/helpers/expectations/be_a.rb +4 -4
  47. data/test/helpers/expectations/change.rb +5 -5
  48. data/test/helpers/expectations/have.rb +4 -4
  49. data/test/helpers/expectations/predicates.rb +4 -4
  50. data/test/helpers/fixtures.rb +44 -18
  51. data/test/helpers/initial_migration_fixture.sql +44 -0
  52. data/test/unit/build_test.rb +51 -0
  53. data/test/unit/commit_test.rb +83 -0
  54. data/test/unit/helpers_test.rb +56 -0
  55. data/test/unit/integrity_test.rb +18 -0
  56. data/test/unit/migrations_test.rb +56 -0
  57. data/test/unit/notifier_test.rb +123 -0
  58. data/test/unit/project_builder_test.rb +108 -0
  59. data/test/unit/project_test.rb +282 -0
  60. data/test/unit/scm_test.rb +54 -0
  61. data/views/_commit_info.haml +24 -0
  62. data/views/build.haml +2 -2
  63. data/views/error.haml +4 -3
  64. data/views/home.haml +3 -5
  65. data/views/integrity.sass +19 -6
  66. data/views/new.haml +6 -6
  67. data/views/project.builder +9 -9
  68. data/views/project.haml +14 -12
  69. metadata +98 -116
  70. data/VERSION.yml +0 -4
  71. data/app.rb +0 -137
  72. data/integrity.gemspec +0 -76
  73. data/lib/integrity/core_ext/string.rb +0 -5
  74. data/test/helpers/expectations/have_tag.rb +0 -128
  75. data/views/_build_info.haml +0 -18
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + "/../helpers"
2
+
3
+ class IntegrityTest < Test::Unit::TestCase
4
+ test "Integrity.new loads configuration from a file" do
5
+ stub(DataMapper).setup { nil }
6
+
7
+ file = File.dirname(__FILE__) + "/../../config/config.sample.yml"
8
+ Integrity.new(file)
9
+
10
+ Integrity.config[:base_uri].should == "http://integrity.domain.tld"
11
+ Integrity.config[:export_directory].should == "/path/to/scm/exports"
12
+ end
13
+
14
+ specify "config is just a hash" do
15
+ Integrity.config[:foo] = "bar"
16
+ Integrity.config[:foo].should == "bar"
17
+ end
18
+ end
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + "/../helpers"
2
+
3
+ class MigrationsTest < Test::Unit::TestCase
4
+ def database_adapter
5
+ DataMapper.repository(:default).adapter
6
+ end
7
+
8
+ def table_exists?(table_name)
9
+ database_adapter.storage_exists?(table_name)
10
+ end
11
+
12
+ def current_migrations
13
+ database_adapter.query("SELECT * from migration_info")
14
+ end
15
+
16
+ def load_initial_migration_fixture
17
+ database_adapter.execute(File.read(File.dirname(__FILE__) +
18
+ "/../helpers/initial_migration_fixture.sql"))
19
+ end
20
+
21
+ before(:all) do
22
+ require "integrity/migrations"
23
+ end
24
+
25
+ before(:each) do
26
+ [Project, Build, Commit, Notifier].each(&:auto_migrate_down!)
27
+ assert !table_exists?("migration_info") # just to be sure
28
+ end
29
+
30
+ test "upgrading a pre migration database" do
31
+ util_capture { Integrity.migrate_db }
32
+
33
+ current_migrations.should == ["initial", "add_commits"]
34
+ assert table_exists?("integrity_projects")
35
+ assert table_exists?("integrity_builds")
36
+ assert table_exists?("integrity_notifiers")
37
+ assert table_exists?("integrity_commits")
38
+ end
39
+
40
+ test "migrating data from initial to add_commits migration" do
41
+ load_initial_migration_fixture
42
+
43
+ util_capture { Integrity.migrate_db }
44
+ current_migrations.should == ["initial", "add_commits"]
45
+
46
+ sinatra = Project.first(:name => "Sinatra")
47
+ sinatra.should have(1).commits
48
+ sinatra.commits.first.should be_successful
49
+ sinatra.commits.first.output.should =~ /sinatra/
50
+
51
+ shout_bot = Project.first(:name => "Shout Bot")
52
+ shout_bot.should have(1).commits
53
+ shout_bot.commits.first.should be_failed
54
+ shout_bot.commits.first.output.should =~ /shout-bot/
55
+ end
56
+ end
@@ -0,0 +1,123 @@
1
+ require File.dirname(__FILE__) + "/../helpers"
2
+
3
+ class NotifierTest < Test::Unit::TestCase
4
+ specify "IRC fixture is valid and can be saved" do
5
+ lambda do
6
+ Notifier.generate(:irc).tap do |project|
7
+ project.should be_valid
8
+ project.save
9
+ end
10
+ end.should change(Project, :count).by(1)
11
+ end
12
+
13
+ specify "Twitter fixture is valid and can be saved" do
14
+ lambda do
15
+ Notifier.generate(:twitter).tap do |project|
16
+ project.should be_valid
17
+ project.save
18
+ end
19
+ end.should change(Project, :count).by(1)
20
+ end
21
+
22
+ describe "Properties" do
23
+ before(:each) do
24
+ @notifier = Notifier.generate(:irc)
25
+ end
26
+
27
+ it "has a name" do
28
+ @notifier.name.should == "IRC"
29
+ end
30
+
31
+ it "has a config" do
32
+ @notifier.config.should == {:uri => "irc://irc.freenode.net/integrity"}
33
+ end
34
+ end
35
+
36
+ describe "Validation" do
37
+ it "requires a name" do
38
+ lambda do
39
+ Notifier.generate(:irc, :name => nil)
40
+ end.should_not change(Notifier, :count)
41
+ end
42
+
43
+ it "requires a config" do
44
+ lambda do
45
+ Notifier.generate(:irc, :config => nil)
46
+ end.should_not change(Notifier, :count)
47
+ end
48
+
49
+ it "requires a project" do
50
+ lambda do
51
+ Notifier.generate(:irc, :project => nil)
52
+ end.should_not change(Notifier, :count)
53
+ end
54
+
55
+ it "requires an unique name in project scope" do
56
+ project = Project.generate
57
+ irc = Notifier.gen(:irc, :project => project)
58
+
59
+ project.tap { |project| project.notifiers << irc }.save
60
+
61
+ lambda do
62
+ project.tap { |project| project.notifiers << irc }.save
63
+ end.should_not change(project.notifiers, :count).from(1).to(2)
64
+
65
+ lambda { Notifier.gen(:irc) }.should change(Notifier, :count).to(2)
66
+ end
67
+ end
68
+
69
+ it "knows which notifiers are available" do
70
+ Notifier.gen(:irc)
71
+ Notifier.gen(:twitter)
72
+ Notifier.should have(2).available
73
+ Notifier.available.should include(Integrity::Notifier::IRC)
74
+ Notifier.available.should include(Integrity::Notifier::Twitter)
75
+ end
76
+
77
+ it "knows how to notify the world of a build" do
78
+ irc = Notifier.generate(:irc)
79
+ build = Integrity::Build.generate
80
+ Notifier::IRC.expects(:notify_of_build).with(build, irc.config)
81
+ irc.notify_of_build(build)
82
+ end
83
+
84
+ describe "Enabling a list of notifiers for a project" do
85
+ it "creates new notifiers for the project" do
86
+ project = Project.generate
87
+ lambda do
88
+ project.enable_notifiers(["IRC", "Twitter"],
89
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"},
90
+ "Twitter" => {"username" => "john"}})
91
+ end.should change(project.notifiers, :count).from(0).to(2)
92
+ end
93
+
94
+ it "deletes all of previous notifiers" do
95
+ project = Project.generate(:notifiers => [Notifier.gen(:irc), Notifier.gen(:twitter)])
96
+ lambda do
97
+ project.enable_notifiers("IRC", {"IRC" => {:foo => "bar"}})
98
+ project.reload
99
+ end.should change(project.notifiers, :count).from(2).to(1)
100
+ end
101
+
102
+ it "does nothing if given nil as the list of notifiers to enable" do
103
+ lambda { Project.gen.enable_notifiers(nil, {}) }.should_not change(Notifier, :count)
104
+ end
105
+
106
+ it "doesn't destroy any of the other notifiers that exist for other projects" do
107
+ irc = Notifier.generate(:irc)
108
+
109
+ project = Project.gen
110
+ project.enable_notifiers("IRC", {"IRC" => irc.config})
111
+
112
+ lambda do
113
+ Project.gen.enable_notifiers("IRC", {"IRC" => irc.config})
114
+ end.should_not change(project.notifiers, :count)
115
+ end
116
+ end
117
+
118
+ it "requires notifier classes to implement Notifier.to_haml and Notifier#deliver!" do
119
+ class Blah < Notifier::Base; end
120
+ lambda { Blah.to_haml }.should raise_error(NoMethodError)
121
+ lambda { Blah.new(Build.gen, {}).deliver! }.should raise_error(NoMethodError)
122
+ end
123
+ end
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + "/../helpers"
2
+
3
+ class ProjectBuilderTest < Test::Unit::TestCase
4
+ before(:all) do
5
+ Integrity.config[:export_directory] = File.dirname(__FILE__)
6
+ @directory = Integrity.config[:export_directory] + "/foca-integrity-master"
7
+ FileUtils.mkdir(@directory)
8
+ end
9
+
10
+ after(:all) do
11
+ FileUtils.rm_rf(@directory)
12
+ end
13
+
14
+ before(:each) do
15
+ @project = Integrity::Project.generate(:integrity, :command => "echo 'output!'")
16
+ ignore_logs!
17
+ end
18
+
19
+ it "creates a new SCM with given project's uri, branch and export_directory" do
20
+ SCM::Git.expects(:new).with(@project.uri, @project.branch, @directory)
21
+ ProjectBuilder.new(@project)
22
+ end
23
+
24
+ describe "When building" do
25
+ before(:each) do
26
+ @commit = @project.commits.gen(:pending)
27
+ end
28
+
29
+ it "sets the started and completed timestamps" do
30
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
31
+ SCM::Git.any_instance.expects(:info).returns({})
32
+
33
+ build = ProjectBuilder.new(@project).build(@commit)
34
+ build.output.should == "output!\n"
35
+ build.started_at.should_not be_nil
36
+ build.completed_at.should_not be_nil
37
+ build.should be_successful
38
+ end
39
+
40
+ it "ensures completed_at is set, even if something horrible happens" do
41
+ lambda {
42
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).raises
43
+ SCM::Git.any_instance.expects(:info).returns({})
44
+
45
+ build = ProjectBuilder.new(@project).build(@commit)
46
+ build.started_at.should_not be_nil
47
+ build.completed_at.should_not be_nil
48
+ build.should be_failed
49
+ }.should raise_error
50
+ end
51
+
52
+
53
+ it "sets the build status to failure when the build command exits with a non-zero status" do
54
+ @project.update_attributes(:command => "exit 1")
55
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
56
+ SCM::Git.any_instance.expects(:info).returns({})
57
+
58
+ build = ProjectBuilder.new(@project).build(@commit)
59
+ build.should be_failed
60
+ end
61
+
62
+ it "sets the build status to success when the build command exits with a zero status" do
63
+ @project.update_attributes(:command => "exit 0")
64
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
65
+ SCM::Git.any_instance.expects(:info).returns({})
66
+
67
+ build = ProjectBuilder.new(@project).build(@commit)
68
+ build.should be_successful
69
+ end
70
+
71
+ it "runs the command in the export directory" do
72
+ @project.update_attributes(:command => "cat foo.txt")
73
+ File.open(@directory + "/foo.txt", "w") { |file| file << "bar!" }
74
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
75
+ SCM::Git.any_instance.expects(:info).returns({})
76
+
77
+ build = ProjectBuilder.new(@project).build(@commit)
78
+ build.output.should == "bar!"
79
+ end
80
+
81
+ it "captures both stdout and stderr" do
82
+ @project.update_attributes(:command => "echo foo through out && echo bar through err 1>&2")
83
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
84
+ SCM::Git.any_instance.expects(:info).returns({})
85
+
86
+ build = ProjectBuilder.new(@project).build(@commit)
87
+ build.output.should == "foo through out\nbar through err\n"
88
+ end
89
+
90
+ it "raises SCMUnknownError if it can't figure the scm from the uri" do
91
+ @project.update_attributes(:uri => "scm://example.org")
92
+ lambda { ProjectBuilder.new(@project) }.should raise_error(SCM::SCMUnknownError)
93
+ end
94
+ end
95
+
96
+ describe "When deleting the code from disk" do
97
+ it "destroys the directory" do
98
+ lambda do
99
+ ProjectBuilder.new(@project).delete_code
100
+ end.should change(Pathname.new(@directory), :directory?).from(true).to(false)
101
+ end
102
+
103
+ it "don't complains if the directory doesn't exists" do
104
+ Pathname.new(@directory).should_not be_directory
105
+ lambda { ProjectBuilder.new(@project).delete_code }.should_not raise_error
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,282 @@
1
+ require File.dirname(__FILE__) + "/../helpers"
2
+
3
+ class ProjectTest < Test::Unit::TestCase
4
+ before(:each) do
5
+ RR.reset
6
+ ignore_logs!
7
+ end
8
+
9
+ specify "default fixture is valid and can be saved" do
10
+ lambda do
11
+ Project.generate.tap do |project|
12
+ project.should be_valid
13
+ project.save
14
+ end
15
+ end.should change(Project, :count).by(1)
16
+ end
17
+
18
+ specify "integrity fixture is valid and can be saved" do
19
+ lambda do
20
+ Project.generate(:integrity).tap do |project|
21
+ project.should be_valid
22
+ project.save
23
+ end
24
+ end.should change(Project, :count).by(1)
25
+ end
26
+
27
+ describe "Properties" do
28
+ before(:each) do
29
+ @project = Project.generate(:integrity)
30
+ end
31
+
32
+ it "has a name" do
33
+ @project.name.should == "Integrity"
34
+ end
35
+
36
+ it "has a permalink" do
37
+ @project.permalink.should == "integrity"
38
+
39
+ @project.tap do |project|
40
+ project.name = "foo's bar/baz and BACON?!"
41
+ project.save
42
+ end.permalink.should == "foos-bar-baz-and-bacon"
43
+ end
44
+
45
+ it "has an URI" do
46
+ @project.uri.should == Addressable::URI.parse("git://github.com/foca/integrity.git")
47
+ end
48
+
49
+ it "has a branch" do
50
+ @project.branch.should == "master"
51
+ end
52
+
53
+ specify "branch defaults to master" do
54
+ Project.new.branch.should == "master"
55
+ end
56
+
57
+ it "has a command" do
58
+ # TODO: rename to build_command
59
+ @project.command.should == "rake"
60
+ end
61
+
62
+ specify "command defaults to 'rake'" do
63
+ Project.new.command.should == "rake"
64
+ end
65
+
66
+ it "has a building flag" do
67
+ @project.should_not be_building
68
+ end
69
+
70
+ specify "building flag default to false" do
71
+ Project.new.should_not be_building
72
+ end
73
+
74
+ it "knows it's visibility" do
75
+ # TODO: rename Project#public property to visibility
76
+ # TODO: and have utility method to query its state instead
77
+
78
+ Project.new.should be_public
79
+
80
+ @project.should be_public
81
+ @project.tap { |p| p.public = "1" }.should be_public
82
+ @project.tap { |p| p.public = "0" }.should_not be_public
83
+
84
+ Project.gen(:public => "false").should be_public
85
+ Project.gen(:public => "true").should be_public
86
+ Project.gen(:public => false).should_not be_public
87
+ Project.gen(:public => nil).should_not be_public
88
+ end
89
+
90
+ it "has a created_at" do
91
+ @project.created_at.should be_a(DateTime)
92
+ end
93
+
94
+ it "has an updated_at" do
95
+ @project.updated_at.should be_a(DateTime)
96
+ end
97
+
98
+ it "knows it's status" do
99
+ Project.gen(:commits => 1.of{ Commit.gen(:successful) }).status.should == :success
100
+ Project.gen(:commits => 2.of{ Commit.gen(:successful) }).status.should == :success
101
+ Project.gen(:commits => 2.of{ Commit.gen(:failed) }).status.should == :failed
102
+ Project.gen(:commits => 1.of{ Commit.gen(:pending) }).status.should == :pending
103
+ Project.gen(:commits => []).status.should be_nil
104
+ end
105
+
106
+ it "knows it's last build" do
107
+ Project.gen(:commits => []).last_commit.should be_nil
108
+
109
+ commits = 5.of { Commit.gen(:successful) }
110
+ project = Project.gen(:commits => commits)
111
+ project.last_commit.should == commits.sort_by {|c| c.committed_at }.last
112
+ end
113
+ end
114
+
115
+ describe "Validation" do
116
+ it "requires a name" do
117
+ lambda do
118
+ Project.gen(:name => nil).should_not be_valid
119
+ end.should_not change(Project, :count)
120
+ end
121
+
122
+ it "requires an URI" do
123
+ lambda do
124
+ Project.gen(:uri => nil).should_not be_valid
125
+ end.should_not change(Project, :count)
126
+ end
127
+
128
+ it "requires a branch" do
129
+ lambda do
130
+ Project.gen(:branch => nil).should_not be_valid
131
+ end.should_not change(Project, :count)
132
+ end
133
+
134
+ it "requires a command" do
135
+ lambda do
136
+ Project.gen(:command => nil).should_not be_valid
137
+ end.should_not change(Project, :count)
138
+ end
139
+
140
+ it "ensures its name is unique" do
141
+ Project.gen(:name => "Integrity")
142
+ lambda do
143
+ Project.gen(:name => "Integrity").should_not be_valid
144
+ end.should_not change(Project, :count)
145
+ end
146
+ end
147
+
148
+ describe "Finding public or private projects" do
149
+ before(:each) do
150
+ @public_project = Project.gen(:public => true)
151
+ @private_project = Project.gen(:public => false)
152
+ end
153
+
154
+ it "finds only public projects if the condition passed is false" do
155
+ projects = Project.only_public_unless(false)
156
+ projects.should_not include(@private_project)
157
+ projects.should include(@public_project)
158
+ end
159
+
160
+ it "finds both private and public projects if the condition passed is true" do
161
+ projects = Project.only_public_unless(true)
162
+ projects.should include(@private_project)
163
+ projects.should include(@public_project)
164
+ end
165
+ end
166
+
167
+ describe "When finding its previous builds" do
168
+ before(:each) do
169
+ @project = Project.generate(:commits => 5.of { Commit.gen })
170
+ @commits = @project.commits.sort_by {|c| c.committed_at }.reverse
171
+ end
172
+
173
+ it "has 4 previous builds" do
174
+ @project.should have(4).previous_commits
175
+ end
176
+
177
+ it "returns the builds ordered chronogicaly (desc) by creation date" do
178
+ @project.previous_commits.should == @commits[1..-1]
179
+ end
180
+
181
+ it "excludes the last build" do
182
+ @project.previous_commits.should_not include(@project.last_commit)
183
+ end
184
+
185
+ it "returns an empty array if it has only one build" do
186
+ project = Project.gen(:commits => 1.of { Integrity::Commit.gen })
187
+ project.should have(:no).previous_commits
188
+ end
189
+
190
+ it "returns an empty array if there are no builds" do
191
+ project = Project.gen(:commits => [])
192
+ project.should have(:no).previous_commits
193
+ end
194
+ end
195
+
196
+ describe "When getting destroyed" do
197
+ before(:each) do
198
+ @commits = 7.of { Commit.gen }
199
+ @project = Project.generate(:commits => @commits)
200
+ end
201
+
202
+ it "destroys itself and tell ProjectBuilder to delete the code from disk" do
203
+ lambda do
204
+ stub.instance_of(ProjectBuilder).delete_code
205
+ @project.destroy
206
+ end.should change(Project, :count).by(-1)
207
+ end
208
+
209
+ it "destroys its builds" do
210
+ lambda do
211
+ @project.destroy
212
+ end.should change(Commit, :count).by(-7)
213
+ end
214
+ end
215
+
216
+ describe "When retrieving state about its notifier" do
217
+ before(:each) do
218
+ @project = Project.generate
219
+ @irc = Notifier.generate(:irc)
220
+ end
221
+
222
+ specify "#config_for returns given notifier's configuration" do
223
+ @project.update_attributes(:notifiers => [@irc])
224
+ @project.config_for("IRC").should == {:uri => "irc://irc.freenode.net/integrity"}
225
+ end
226
+
227
+ specify "#config_for returns an empty hash if no such notifier" do
228
+ @project.config_for("IRC").should == {}
229
+ end
230
+
231
+ specify "#notifies? is true if it uses the given notifier" do
232
+ @project.update_attributes(:notifiers => [@irc])
233
+ @project.notifies?("IRC").should == true
234
+ end
235
+
236
+ specify "#notifies? is false if it doesnt use the given notifier" do
237
+ @project.update_attributes(:notifiers => [])
238
+
239
+ @project.notifies?("IRC").should == false
240
+ @project.notifies?("UndefinedNotifier").should == false
241
+ end
242
+ end
243
+
244
+ describe "When building a commit" do
245
+ before(:each) do
246
+ @commits = 2.of { Commit.gen }
247
+ @project = Project.gen(:integrity, :commits => @commits)
248
+ stub.instance_of(ProjectBuilder).build { nil }
249
+ end
250
+
251
+ it "gets the specified commit and creates a pending build for it" do
252
+ commit = @commits.last
253
+
254
+ lambda {
255
+ @project.build(commit.identifier)
256
+ }.should change(Build, :count).by(1)
257
+
258
+ build = Build.all.last
259
+ build.commit.should be(commit)
260
+ build.should be_pending
261
+
262
+ commit.should be_pending
263
+ end
264
+
265
+ it "creates an empty commit with the head of the project if passed 'HEAD' (the default)" do
266
+ mock(@project).head_of_remote_repo { "FOOBAR" }
267
+
268
+ lambda {
269
+ @project.build("HEAD")
270
+ }.should change(Commit, :count).by(1)
271
+
272
+ build = Build.all.last
273
+ build.commit.should be(@project.last_commit)
274
+
275
+ @project.last_commit.should be_pending
276
+ @project.last_commit.identifier.should be("FOOBAR")
277
+
278
+ @project.last_commit.author.name.should == "<Commit author not loaded>"
279
+ @project.last_commit.message.should == "<Commit message not loaded>"
280
+ end
281
+ end
282
+ end