gforces-integrity 0.1.9.3

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 (94) hide show
  1. data/.gitignore +12 -0
  2. data/CHANGES +42 -0
  3. data/README.md +82 -0
  4. data/Rakefile +57 -0
  5. data/bin/integrity +4 -0
  6. data/config/config.sample.ru +21 -0
  7. data/config/config.sample.yml +41 -0
  8. data/config/heroku/.gems +1 -0
  9. data/config/heroku/Rakefile +6 -0
  10. data/config/heroku/config.ru +7 -0
  11. data/config/heroku/integrity-config.rb +14 -0
  12. data/config/thin.sample.yml +13 -0
  13. data/integrity.gemspec +138 -0
  14. data/lib/integrity.rb +78 -0
  15. data/lib/integrity/app.rb +138 -0
  16. data/lib/integrity/author.rb +39 -0
  17. data/lib/integrity/build.rb +52 -0
  18. data/lib/integrity/commit.rb +60 -0
  19. data/lib/integrity/core_ext/object.rb +6 -0
  20. data/lib/integrity/helpers.rb +16 -0
  21. data/lib/integrity/helpers/authorization.rb +33 -0
  22. data/lib/integrity/helpers/breadcrumbs.rb +20 -0
  23. data/lib/integrity/helpers/forms.rb +29 -0
  24. data/lib/integrity/helpers/pretty_output.rb +45 -0
  25. data/lib/integrity/helpers/rendering.rb +25 -0
  26. data/lib/integrity/helpers/resources.rb +19 -0
  27. data/lib/integrity/helpers/urls.rb +59 -0
  28. data/lib/integrity/installer.rb +138 -0
  29. data/lib/integrity/migrations.rb +151 -0
  30. data/lib/integrity/notifier.rb +44 -0
  31. data/lib/integrity/notifier/base.rb +74 -0
  32. data/lib/integrity/notifier/test.rb +59 -0
  33. data/lib/integrity/notifier/test/fixtures.rb +108 -0
  34. data/lib/integrity/notifier/test/hpricot_matcher.rb +38 -0
  35. data/lib/integrity/project.rb +100 -0
  36. data/lib/integrity/project/notifiers.rb +33 -0
  37. data/lib/integrity/project/push.rb +44 -0
  38. data/lib/integrity/project_builder.rb +56 -0
  39. data/lib/integrity/scm.rb +21 -0
  40. data/lib/integrity/scm/git.rb +89 -0
  41. data/lib/integrity/scm/git/uri.rb +57 -0
  42. data/public/buttons.css +82 -0
  43. data/public/reset.css +7 -0
  44. data/public/spinner.gif +0 -0
  45. data/test/acceptance/api_test.rb +97 -0
  46. data/test/acceptance/browse_project_builds_test.rb +65 -0
  47. data/test/acceptance/browse_project_test.rb +99 -0
  48. data/test/acceptance/build_notifications_test.rb +95 -0
  49. data/test/acceptance/create_project_test.rb +97 -0
  50. data/test/acceptance/delete_project_test.rb +53 -0
  51. data/test/acceptance/edit_project_test.rb +117 -0
  52. data/test/acceptance/error_page_test.rb +18 -0
  53. data/test/acceptance/installer_test.rb +79 -0
  54. data/test/acceptance/manual_build_project_test.rb +82 -0
  55. data/test/acceptance/not_found_page_test.rb +29 -0
  56. data/test/acceptance/project_syndication_test.rb +30 -0
  57. data/test/acceptance/stylesheet_test.rb +26 -0
  58. data/test/acceptance/unauthorized_page_test.rb +20 -0
  59. data/test/helpers.rb +82 -0
  60. data/test/helpers/acceptance.rb +83 -0
  61. data/test/helpers/acceptance/email_notifier.rb +55 -0
  62. data/test/helpers/acceptance/git_helper.rb +99 -0
  63. data/test/helpers/acceptance/notifier_helper.rb +47 -0
  64. data/test/helpers/acceptance/textfile_notifier.rb +26 -0
  65. data/test/helpers/expectations.rb +4 -0
  66. data/test/helpers/expectations/be_a.rb +23 -0
  67. data/test/helpers/expectations/change.rb +90 -0
  68. data/test/helpers/expectations/have.rb +105 -0
  69. data/test/helpers/expectations/predicates.rb +37 -0
  70. data/test/helpers/initial_migration_fixture.sql +44 -0
  71. data/test/unit/build_test.rb +72 -0
  72. data/test/unit/commit_test.rb +66 -0
  73. data/test/unit/helpers_test.rb +103 -0
  74. data/test/unit/integrity_test.rb +35 -0
  75. data/test/unit/migrations_test.rb +57 -0
  76. data/test/unit/notifier/base_test.rb +43 -0
  77. data/test/unit/notifier/test_test.rb +29 -0
  78. data/test/unit/notifier_test.rb +97 -0
  79. data/test/unit/project_builder_test.rb +118 -0
  80. data/test/unit/project_test.rb +363 -0
  81. data/test/unit/scm_test.rb +54 -0
  82. data/views/_commit_info.haml +24 -0
  83. data/views/build.haml +2 -0
  84. data/views/error.haml +37 -0
  85. data/views/home.haml +21 -0
  86. data/views/integrity.sass +400 -0
  87. data/views/layout.haml +29 -0
  88. data/views/new.haml +50 -0
  89. data/views/not_found.haml +31 -0
  90. data/views/notifier.haml +7 -0
  91. data/views/project.builder +21 -0
  92. data/views/project.haml +30 -0
  93. data/views/unauthorized.haml +38 -0
  94. metadata +325 -0
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + "/../../helpers"
2
+ require "helpers/acceptance/textfile_notifier"
3
+
4
+ require "integrity/notifier/test"
5
+
6
+ class NotifierTestTest < Test::Unit::TestCase
7
+ include Integrity::Notifier::Test
8
+
9
+ before(:each) do
10
+ # Because we unset every notifier in global setup
11
+ load "helpers/acceptance/textfile_notifier.rb"
12
+ end
13
+
14
+ def notifier
15
+ "Textfile"
16
+ end
17
+
18
+ test "it provides a formulary to configure options" do
19
+ assert_form_have_option("file")
20
+ end
21
+
22
+ test "it sends notification" do
23
+ commit = Integrity::Commit.gen(:build => Build.gen(:successful))
24
+
25
+ assert notification(commit).include?(commit.identifier)
26
+ assert notification_failed.include?("failed")
27
+ assert notification_successful.include?("was successful")
28
+ end
29
+ end
@@ -0,0 +1,97 @@
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
+ describe "Registering a notifier" do
70
+ it "registers given notifier class" do
71
+ load "helpers/acceptance/textfile_notifier.rb"
72
+
73
+ Notifier.register(Integrity::Notifier::Textfile)
74
+
75
+ assert_equal Integrity::Notifier::Textfile,
76
+ Notifier.available["Textfile"]
77
+ end
78
+
79
+ it "raises ArgumentError if given class is not a valid notifier" do
80
+ assert_raise(ArgumentError) {
81
+ Notifier.register(Class.new)
82
+ }
83
+
84
+ assert Notifier.available.empty?
85
+ end
86
+ end
87
+
88
+ it "knows how to notify the world of a build" do
89
+ irc = Notifier.gen(:irc)
90
+ Notifier.register(Integrity::Notifier::IRC)
91
+ build = Build.gen
92
+
93
+ mock(Notifier::IRC).notify_of_build(build, irc.config) { nil }
94
+
95
+ irc.notify_of_build(build)
96
+ end
97
+ end
@@ -0,0 +1,118 @@
1
+ require File.dirname(__FILE__) + "/../helpers"
2
+
3
+ class ProjectBuilderTest < Test::Unit::TestCase
4
+ before(:all) do
5
+ unless File.directory?(Integrity.config[:export_directory])
6
+ FileUtils.mkdir(Integrity.config[:export_directory])
7
+ end
8
+
9
+ @directory = Integrity.config[:export_directory] + "/foca-integrity-master"
10
+ FileUtils.mkdir(@directory)
11
+ end
12
+
13
+ after(:all) do
14
+ FileUtils.rm_rf(@directory)
15
+ end
16
+
17
+ before(:each) do
18
+ @project = Integrity::Project.generate(:integrity, :command => "echo 'output!'")
19
+ ignore_logs!
20
+ end
21
+
22
+ it "creates a new SCM with given project's uri, branch and export_directory" do
23
+ SCM::Git.expects(:new).with(@project.uri, @project.branch, @directory)
24
+ ProjectBuilder.new(@project)
25
+ end
26
+
27
+ describe "When building" do
28
+ before(:each) do
29
+ @commit = @project.commits.gen(:pending)
30
+ end
31
+
32
+ it "sets the started and completed timestamps" do
33
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
34
+ SCM::Git.any_instance.expects(:info).returns({})
35
+
36
+ build = ProjectBuilder.new(@project).build(@commit)
37
+ build.output.should == "output!\n"
38
+ build.started_at.should_not be_nil
39
+ build.completed_at.should_not be_nil
40
+ build.should be_successful
41
+ end
42
+
43
+ it "ensures completed_at is set, even if something horrible happens" do
44
+ lambda {
45
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).raises
46
+ SCM::Git.any_instance.expects(:info).returns({})
47
+
48
+ build = ProjectBuilder.new(@project).build(@commit)
49
+ build.started_at.should_not be_nil
50
+ build.completed_at.should_not be_nil
51
+ build.should be_failed
52
+ }.should raise_error
53
+ end
54
+
55
+ it "sets the build status to failure when the build command exits with a non-zero status" do
56
+ @project.update_attributes(:command => "exit 1")
57
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
58
+ SCM::Git.any_instance.expects(:info).returns({})
59
+
60
+ build = ProjectBuilder.new(@project).build(@commit)
61
+ build.should be_failed
62
+ end
63
+
64
+ it "sets the build status to success when the build command exits with a zero status" do
65
+ @project.update_attributes(:command => "exit 0")
66
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
67
+ SCM::Git.any_instance.expects(:info).returns({})
68
+
69
+ build = ProjectBuilder.new(@project).build(@commit)
70
+ build.should be_successful
71
+ end
72
+
73
+ it "runs the command in the export directory" do
74
+ @project.update_attributes(:command => "cat foo.txt")
75
+ File.open(@directory + "/foo.txt", "w") { |file| file << "bar!" }
76
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
77
+ SCM::Git.any_instance.expects(:info).returns({})
78
+
79
+ build = ProjectBuilder.new(@project).build(@commit)
80
+ build.output.should == "bar!"
81
+ end
82
+
83
+ it "captures both stdout and stderr" do
84
+ @project.update_attributes(:command => "echo foo through out && echo bar through err 1>&2")
85
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
86
+ SCM::Git.any_instance.expects(:info).returns({})
87
+
88
+ build = ProjectBuilder.new(@project).build(@commit)
89
+ build.output.should == "foo through out\nbar through err\n"
90
+ end
91
+
92
+ it "raises SCMUnknownError if it can't figure the scm from the uri" do
93
+ @project.update_attributes(:uri => "scm://example.org")
94
+ lambda { ProjectBuilder.new(@project) }.should raise_error(SCM::SCMUnknownError)
95
+ end
96
+
97
+ it "doesn't fail if the commit identifier can't be retrieved" do
98
+ SCM::Git.any_instance.expects(:with_revision).with(@commit.identifier).yields
99
+ SCM::Git.any_instance.expects(:info).returns(false)
100
+ lambda {
101
+ ProjectBuilder.new(@project).build(@commit)
102
+ }.should_not raise_error
103
+ end
104
+ end
105
+
106
+ describe "When deleting the code from disk" do
107
+ it "destroys the directory" do
108
+ lambda do
109
+ ProjectBuilder.new(@project).delete_code
110
+ end.should change(Pathname.new(@directory), :directory?).from(true).to(false)
111
+ end
112
+
113
+ it "don't complains if the directory doesn't exists" do
114
+ Pathname.new(@directory).should_not be_directory
115
+ lambda { ProjectBuilder.new(@project).delete_code }.should_not raise_error
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,363 @@
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 updating its notifiers" do
217
+ setup do
218
+ twitter = Notifier.gen(:twitter, :enabled => true)
219
+ irc = Notifier.gen(:irc, :enabled => false)
220
+
221
+ @project = Project.gen(:notifiers => [twitter, irc])
222
+ end
223
+
224
+ it "creates and enable the given notifiers" do
225
+ Notifier.all.destroy!
226
+
227
+ project = Project.gen
228
+ project.update_notifiers(["IRC", "Twitter"],
229
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"},
230
+ "Twitter" => {"username" => "john"}})
231
+
232
+ assert_equal 2, Notifier.count
233
+ assert_equal 2, project.enabled_notifiers.count
234
+ assert_equal "IRC", project.notifiers.first.name
235
+ assert_equal "Twitter", project.notifiers.last.name
236
+
237
+ project.update_notifiers(["Twitter"],
238
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"},
239
+ "Twitter" => {"username" => "john"}})
240
+
241
+ assert_equal 2, Notifier.count
242
+ assert ! project.notifies?("IRC")
243
+ assert project.notifies?("Twitter")
244
+ end
245
+
246
+ it "creates notifiers present in config even when they're disabled" do
247
+ @project.update_notifiers(["IRC"],
248
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"},
249
+ "Twitter" => {"username" => "john"}})
250
+
251
+ assert_equal 2, @project.notifiers.count
252
+ end
253
+
254
+ it "disables notifiers that are not included in the list" do
255
+ @project.update_notifiers(["IRC"],
256
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"},
257
+ "Twitter" => {"username" => "john"}})
258
+
259
+ @project.update_notifiers(["IRC"],
260
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"}})
261
+
262
+ assert ! @project.notifiers.first(:name => "Twitter").enabled?
263
+ assert @project.notifiers.first(:name => "IRC").enabled?
264
+ end
265
+
266
+ it "preserves config of notifiers that are being disabled" do
267
+ @project.update_notifiers(["IRC"],
268
+ {"IRC" => {"uri" => "irc://irc.freenode.net/integrity"},
269
+ "Twitter" => {"username" => "john"}})
270
+
271
+ assert_equal "john",
272
+ @project.notifiers.first(:name => "Twitter").config["username"]
273
+ end
274
+
275
+ it "does nothing if given nil as the list of notifiers to enable" do
276
+ lambda { Project.gen.update_notifiers(nil, {}) }.should_not change(Notifier, :count)
277
+ end
278
+
279
+ it "doesn't destroy any of the other notifiers that exist for other projects" do
280
+ irc = Notifier.generate(:irc)
281
+
282
+ project = Project.gen
283
+ project.update_notifiers("IRC", {"IRC" => irc.config})
284
+
285
+ lambda {
286
+ Project.gen.update_notifiers("IRC", {"IRC" => irc.config})
287
+ }.should_not change(project.notifiers, :count)
288
+ end
289
+ end
290
+
291
+ describe "When retrieving state about its notifier" do
292
+ before(:each) do
293
+ @project = Project.gen
294
+ @irc = Notifier.generate(:irc)
295
+ end
296
+
297
+ it "knows which notifiers are enabled" do
298
+ notifiers = [Notifier.gen(:irc, :enabled => false),
299
+ Notifier.gen(:twitter, :enabled => true)]
300
+ project = Project.gen(:notifiers => notifiers)
301
+
302
+ assert_equal 1, project.enabled_notifiers.size
303
+ end
304
+
305
+ specify "#config_for returns given notifier's configuration" do
306
+ @project.update_attributes(:notifiers => [@irc])
307
+ @project.config_for("IRC").should == {:uri => "irc://irc.freenode.net/integrity"}
308
+ end
309
+
310
+ specify "#config_for returns an empty hash for unknown notifier" do
311
+ @project.config_for("IRC").should == {}
312
+ end
313
+
314
+ specify "#notifies? is true if the notifier exists and is enabled" do
315
+ assert ! @project.notifies?("UndefinedNotifier")
316
+
317
+ @project.update_attributes(:notifiers =>
318
+ [ Notifier.gen(:irc, :enabled => true),
319
+ Notifier.gen(:twitter, :enabled => false) ])
320
+
321
+ assert @project.notifies?("IRC")
322
+ assert ! @project.notifies?("Twitter")
323
+ end
324
+ end
325
+
326
+ describe "When building a commit" do
327
+ before(:each) do
328
+ @commits = 2.of { Commit.gen }
329
+ @project = Project.gen(:integrity, :commits => @commits)
330
+ stub.instance_of(ProjectBuilder).build { nil }
331
+ end
332
+
333
+ it "gets the specified commit and creates a pending build for it" do
334
+ commit = @commits.last
335
+
336
+ lambda {
337
+ @project.build(commit.identifier)
338
+ }.should change(Build, :count).by(1)
339
+
340
+ build = Build.all.last
341
+ build.commit.should be(commit)
342
+ build.should be_pending
343
+
344
+ commit.should be_pending
345
+ end
346
+
347
+ it "creates an empty commit with the head of the project if passed 'HEAD' (the default)" do
348
+ mock(@project).head_of_remote_repo { "FOOBAR" }
349
+
350
+ lambda {
351
+ @project.build("HEAD")
352
+ }.should change(Commit, :count).by(1)
353
+
354
+ build = Build.all.last
355
+ build.commit.should == @project.last_commit
356
+
357
+ @project.last_commit.should be_pending
358
+ @project.last_commit.identifier.should == "FOOBAR"
359
+ @project.last_commit.author.name.should == "<Commit author not loaded>"
360
+ @project.last_commit.message.should == "<Commit message not loaded>"
361
+ end
362
+ end
363
+ end