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.
- data/README.markdown +7 -0
- data/Rakefile +77 -124
- data/config/config.ru +29 -0
- data/config/config.sample.ru +6 -16
- data/config/config.sample.yml +15 -12
- data/config/config.yml +34 -0
- data/lib/integrity.rb +13 -13
- data/lib/integrity/app.rb +138 -0
- data/lib/integrity/author.rb +39 -0
- data/lib/integrity/build.rb +54 -31
- data/lib/integrity/commit.rb +71 -0
- data/lib/integrity/helpers.rb +3 -3
- data/lib/integrity/helpers/authorization.rb +2 -2
- data/lib/integrity/helpers/forms.rb +3 -3
- data/lib/integrity/helpers/pretty_output.rb +1 -1
- data/lib/integrity/helpers/rendering.rb +6 -1
- data/lib/integrity/helpers/resources.rb +9 -3
- data/lib/integrity/helpers/urls.rb +15 -13
- data/lib/integrity/installer.rb +43 -60
- data/lib/integrity/migrations.rb +31 -48
- data/lib/integrity/notifier.rb +14 -16
- data/lib/integrity/notifier/base.rb +29 -19
- data/lib/integrity/notifier/test_helpers.rb +100 -0
- data/lib/integrity/project.rb +69 -33
- data/lib/integrity/project_builder.rb +23 -14
- data/lib/integrity/scm/git.rb +15 -14
- data/lib/integrity/scm/git/uri.rb +9 -9
- data/test/acceptance/api_test.rb +97 -0
- data/test/acceptance/browse_project_builds_test.rb +65 -0
- data/test/acceptance/browse_project_test.rb +95 -0
- data/test/acceptance/build_notifications_test.rb +42 -0
- data/test/acceptance/create_project_test.rb +97 -0
- data/test/acceptance/delete_project_test.rb +53 -0
- data/test/acceptance/edit_project_test.rb +117 -0
- data/test/acceptance/error_page_test.rb +18 -0
- data/test/acceptance/helpers.rb +2 -0
- data/test/acceptance/installer_test.rb +62 -0
- data/test/acceptance/manual_build_project_test.rb +82 -0
- data/test/acceptance/notifier_test.rb +109 -0
- data/test/acceptance/project_syndication_test.rb +30 -0
- data/test/acceptance/stylesheet_test.rb +18 -0
- data/test/helpers.rb +59 -26
- data/test/helpers/acceptance.rb +19 -65
- data/test/helpers/acceptance/email_notifier.rb +55 -0
- data/test/helpers/acceptance/git_helper.rb +15 -15
- data/test/helpers/acceptance/textfile_notifier.rb +3 -3
- data/test/helpers/expectations.rb +0 -1
- data/test/helpers/expectations/be_a.rb +4 -4
- data/test/helpers/expectations/change.rb +5 -5
- data/test/helpers/expectations/have.rb +4 -4
- data/test/helpers/expectations/predicates.rb +4 -4
- data/test/helpers/fixtures.rb +44 -18
- data/test/helpers/initial_migration_fixture.sql +44 -0
- data/test/unit/build_test.rb +51 -0
- data/test/unit/commit_test.rb +83 -0
- data/test/unit/helpers_test.rb +56 -0
- data/test/unit/integrity_test.rb +18 -0
- data/test/unit/migrations_test.rb +56 -0
- data/test/unit/notifier_test.rb +123 -0
- data/test/unit/project_builder_test.rb +108 -0
- data/test/unit/project_test.rb +282 -0
- data/test/unit/scm_test.rb +54 -0
- data/views/_commit_info.haml +24 -0
- data/views/build.haml +2 -2
- data/views/error.haml +4 -3
- data/views/home.haml +3 -5
- data/views/integrity.sass +19 -6
- data/views/new.haml +6 -6
- data/views/project.builder +9 -9
- data/views/project.haml +14 -12
- metadata +89 -122
- data/VERSION.yml +0 -4
- data/app.rb +0 -138
- data/integrity.gemspec +0 -76
- data/lib/integrity/core_ext/string.rb +0 -5
- data/test/helpers/expectations/have_tag.rb +0 -128
- data/views/_build_info.haml +0 -18
@@ -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
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../helpers"
|
2
|
+
|
3
|
+
class SCMTest < Test::Unit::TestCase
|
4
|
+
def scm(uri)
|
5
|
+
SCM.new(Addressable::URI.parse(uri), "master", "foo")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "recognizes git URIs" do
|
9
|
+
scm("git://example.org/repo").should be_an(SCM::Git)
|
10
|
+
scm("git@example.org/repo.git").should be_an(SCM::Git)
|
11
|
+
scm("git://example.org/repo.git").should be_an(SCM::Git)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "raises SCMUnknownError if it can't figure the SCM from the URI" do
|
15
|
+
lambda { scm("scm://example.org") }.should raise_error(SCM::SCMUnknownError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "doesn't need the working tree path for all operations, so it's not required on the constructor" do
|
19
|
+
lambda {
|
20
|
+
SCM.new(Addressable::URI.parse("git://github.com/foca/integrity.git"), "master")
|
21
|
+
}.should_not raise_error
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "SCM::Git::URI" do
|
25
|
+
uris = [
|
26
|
+
"rsync://host.xz/path/to/repo.git/",
|
27
|
+
"rsync://host.xz/path/to/repo.git",
|
28
|
+
"rsync://host.xz/path/to/repo.gi",
|
29
|
+
"http://host.xz/path/to/repo.git/",
|
30
|
+
"https://host.xz/path/to/repo.git/",
|
31
|
+
"git://host.xz/path/to/repo.git/",
|
32
|
+
"git://host.xz/~user/path/to/repo.git/",
|
33
|
+
"ssh://[user@]host.xz[:port]/path/to/repo.git/",
|
34
|
+
"ssh://[user@]host.xz/path/to/repo.git/",
|
35
|
+
"ssh://[user@]host.xz/~user/path/to/repo.git/",
|
36
|
+
"ssh://[user@]host.xz/~/path/to/repo.git",
|
37
|
+
"host.xz:/path/to/repo.git/",
|
38
|
+
"host.xz:~user/path/to/repo.git/",
|
39
|
+
"host.xz:path/to/repo.git",
|
40
|
+
"user@host.xz:/path/to/repo.git/",
|
41
|
+
"user@host.xz:~user/path/to/repo.git/",
|
42
|
+
"user@host.xz:path/to/repo.git",
|
43
|
+
"user@host.xz:path/to/repo",
|
44
|
+
"user@host.xz:path/to/repo.a_git"
|
45
|
+
]
|
46
|
+
|
47
|
+
uris.each do |uri|
|
48
|
+
it "parses the uri #{uri}" do
|
49
|
+
git_url = SCM::Git::URI.new(uri)
|
50
|
+
git_url.working_tree_path.should == "path-to-repo"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
%h1&= commit.human_readable_status
|
2
|
+
|
3
|
+
- if commit.failed?
|
4
|
+
%form{ :action => commit_path(commit, :builds), :method => :post }
|
5
|
+
%p.submit
|
6
|
+
%button{ :type => :submit, :title => "Rebuild this commit" }<
|
7
|
+
Rebuild
|
8
|
+
|
9
|
+
%blockquote
|
10
|
+
%p&= commit.message
|
11
|
+
%p.meta<
|
12
|
+
%span.who<
|
13
|
+
&== by: #{commit.author.name}
|
14
|
+
|
|
15
|
+
%span.when{ :title => commit.commited_at }<
|
16
|
+
&= pretty_date commit.committed_at
|
17
|
+
|
|
18
|
+
%span.what<
|
19
|
+
&== commit: #{commit.identifier}
|
20
|
+
|
21
|
+
%h2 Build Output:
|
22
|
+
%pre.output
|
23
|
+
:preserve
|
24
|
+
#{bash_color_codes h(commit.output)}
|
data/views/build.haml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
#build{ :class => @
|
2
|
-
= partial(:
|
1
|
+
#build{ :class => @commit.status }
|
2
|
+
= partial(:commit_info, :commit => @commit)
|
data/views/error.haml
CHANGED
@@ -13,9 +13,10 @@
|
|
13
13
|
|
14
14
|
%dt What can I do?
|
15
15
|
%dd
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
- if @project
|
17
|
+
Is your
|
18
|
+
%a{ :href => project_url(@project, :edit) } config
|
19
|
+
ok?
|
19
20
|
Need
|
20
21
|
%a{ :href => "http://integrityapp.com/configure" } help?
|
21
22
|
Remember to restart Integrity.
|
data/views/home.haml
CHANGED
@@ -8,16 +8,14 @@
|
|
8
8
|
- else
|
9
9
|
%ul#projects
|
10
10
|
- @projects.each do |project|
|
11
|
-
%li{ :class => cycle("even", "odd") +
|
11
|
+
%li{ :class => cycle("even", "odd") + ' ' + project.status.to_s }
|
12
12
|
%a{ :href => project_path(project) }&= project.name
|
13
13
|
.meta
|
14
14
|
- if project.building?
|
15
15
|
Building!
|
16
|
-
- elsif project.
|
16
|
+
- elsif project.last_commit.nil?
|
17
17
|
Never built yet
|
18
18
|
- else
|
19
|
-
|
20
|
-
= pretty_date(project.last_build.created_at)
|
21
|
-
= project.last_build.successful? ? "successfully" : "and failed"
|
19
|
+
= project.human_readable_status
|
22
20
|
%p#new
|
23
21
|
%a{ :href => "/new" } Add a new project
|
data/views/integrity.sass
CHANGED
@@ -108,6 +108,7 @@ a
|
|
108
108
|
:width 30em
|
109
109
|
:padding .2em .4em
|
110
110
|
:color = !title_color
|
111
|
+
input.text
|
111
112
|
:height 1.4em
|
112
113
|
label
|
113
114
|
:float left
|
@@ -177,11 +178,22 @@ a
|
|
177
178
|
:content "."
|
178
179
|
:text-indent -9999em
|
179
180
|
:text-align left
|
180
|
-
&.destroy
|
181
|
-
:margin-top 0
|
181
|
+
&.destroy, &.manual-build
|
182
182
|
button
|
183
183
|
:float none
|
184
184
|
:display inline
|
185
|
+
&.manual-build
|
186
|
+
button
|
187
|
+
:margin-right 0
|
188
|
+
|
189
|
+
#build form, #last_build form
|
190
|
+
:font-size .75em
|
191
|
+
p.submit
|
192
|
+
:margin 0
|
193
|
+
:padding 0
|
194
|
+
:position absolute
|
195
|
+
:right .5em
|
196
|
+
:top 1.25em
|
185
197
|
|
186
198
|
.blank_slate, .error
|
187
199
|
p
|
@@ -213,7 +225,7 @@ a
|
|
213
225
|
:family = !nice_fonts
|
214
226
|
dd
|
215
227
|
:line-height 1.4
|
216
|
-
|
228
|
+
|
217
229
|
.backtrace
|
218
230
|
:margin 1em 0
|
219
231
|
:overflow scroll
|
@@ -254,8 +266,8 @@ a
|
|
254
266
|
:color = !success_color
|
255
267
|
&.failed .meta
|
256
268
|
:color = !failed_color
|
257
|
-
|
258
|
-
|
269
|
+
|
270
|
+
|
259
271
|
#previous_builds
|
260
272
|
li
|
261
273
|
a
|
@@ -288,9 +300,10 @@ a
|
|
288
300
|
:color = !failed_bg - #444
|
289
301
|
&:hover
|
290
302
|
:background-color = !failed_bg + #222
|
291
|
-
|
303
|
+
|
292
304
|
|
293
305
|
#build, #last_build
|
306
|
+
:position relative
|
294
307
|
h1, blockquote
|
295
308
|
:border
|
296
309
|
:width 0 1px
|