tfs_graph 0.1.1 → 0.1.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile +12 -4
  4. data/Rakefile +1 -0
  5. data/lib/tfs_graph.rb +1 -2
  6. data/lib/tfs_graph/abstract_store.rb +23 -0
  7. data/lib/tfs_graph/associators/branch_associator.rb +1 -1
  8. data/lib/tfs_graph/associators/changeset_tree_builder.rb +29 -0
  9. data/lib/tfs_graph/behaviors.rb +9 -0
  10. data/lib/tfs_graph/behaviors/neo4j_repository/branch.rb +39 -0
  11. data/lib/tfs_graph/behaviors/neo4j_repository/changeset.rb +12 -0
  12. data/lib/tfs_graph/behaviors/neo4j_repository/project.rb +89 -0
  13. data/lib/tfs_graph/behaviors/related_repository/branch.rb +26 -0
  14. data/lib/tfs_graph/behaviors/related_repository/changeset.rb +8 -0
  15. data/lib/tfs_graph/behaviors/related_repository/project.rb +48 -0
  16. data/lib/tfs_graph/branch.rb +84 -37
  17. data/lib/tfs_graph/branch/branch_archive_handler.rb +10 -6
  18. data/lib/tfs_graph/branch/branch_store.rb +13 -26
  19. data/lib/tfs_graph/changeset.rb +46 -25
  20. data/lib/tfs_graph/changeset/changeset_normalizer.rb +1 -0
  21. data/lib/tfs_graph/changeset/changeset_store.rb +13 -36
  22. data/lib/tfs_graph/changeset_merge.rb +20 -18
  23. data/lib/tfs_graph/changeset_merge/changeset_merge_store.rb +13 -10
  24. data/lib/tfs_graph/config.rb +12 -4
  25. data/lib/tfs_graph/entity.rb +34 -6
  26. data/lib/tfs_graph/extensions.rb +27 -0
  27. data/lib/tfs_graph/graph_populator.rb +9 -1
  28. data/lib/tfs_graph/persistable_entity.rb +60 -0
  29. data/lib/tfs_graph/populators/everything.rb +16 -4
  30. data/lib/tfs_graph/populators/for_archived_branch.rb +28 -0
  31. data/lib/tfs_graph/populators/for_branch.rb +35 -0
  32. data/lib/tfs_graph/populators/for_project.rb +22 -5
  33. data/lib/tfs_graph/populators/since_date.rb +21 -5
  34. data/lib/tfs_graph/populators/since_last.rb +22 -10
  35. data/lib/tfs_graph/populators/utilities.rb +4 -19
  36. data/lib/tfs_graph/project.rb +49 -13
  37. data/lib/tfs_graph/project/project_store.rb +13 -22
  38. data/lib/tfs_graph/repository.rb +78 -0
  39. data/lib/tfs_graph/repository/neo4j_repository.rb +97 -0
  40. data/lib/tfs_graph/repository/related_repository.rb +89 -0
  41. data/lib/tfs_graph/repository_registry.rb +60 -0
  42. data/lib/tfs_graph/server_registry.rb +45 -0
  43. data/lib/tfs_graph/store_helpers.rb +4 -5
  44. data/lib/tfs_graph/version.rb +1 -1
  45. data/schema.cypher +7 -0
  46. data/spec/branch_spec.rb +120 -0
  47. data/spec/neo4j_repository_integration_spec.rb +346 -0
  48. data/spec/persistable_entity_spec.rb +91 -0
  49. data/spec/project_spec.rb +29 -0
  50. data/spec/related_repository_integration_spec.rb +328 -0
  51. data/spec/repository_registry_spec.rb +48 -0
  52. data/spec/repository_spec.rb +73 -0
  53. data/spec/server_registery_spec.rb +36 -0
  54. data/spec/spec_helper.rb +12 -24
  55. data/tfs_graph.gemspec +3 -2
  56. metadata +67 -21
  57. data/lib/tfs_graph/associators/changeset_tree_creator.rb +0 -19
  58. data/spec/factories.rb +0 -20
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ require 'tfs_graph/repository'
4
+ require 'tfs_graph/repository_registry'
5
+ require 'tfs_graph/persistable_entity'
6
+
7
+ require 'tfs_graph/branch'
8
+ require 'tfs_graph/project'
9
+ require 'tfs_graph/changeset'
10
+
11
+ describe TFSGraph::PersistableEntity do
12
+ Given(:repo_class) { flexmock("FakeRepository") }
13
+ Given(:repo) { flexmock("fake repository instance") }
14
+ Given { TFSGraph::RepositoryRegistry.register {|r| r.type repo_class } }
15
+
16
+ Given { repo_class.should_receive(:new).and_return(repo) }
17
+
18
+ shared_examples "an entity" do
19
+ context "knows when it is not persisted" do
20
+ Then { entity.should_not be_persisted }
21
+ And { repo.should_not have_received(:save) }
22
+ end
23
+
24
+ context "can be persisted" do
25
+ Given { repo.should_receive(:save).with(entity).and_return { entity.persist 1, flexmock(id: 1) } }
26
+ When { entity.save! }
27
+ Then { entity.should be_persisted }
28
+ And { entity.id.should == 1 }
29
+ end
30
+
31
+ context "can convert to a hash" do
32
+ When(:result) { entity.to_hash }
33
+ Then { result.keys.should == (entity.send(:schema).keys << :id).uniq }
34
+ end
35
+
36
+ context "can get repo for self" do
37
+ When(:me) { entity.class.repository }
38
+ Then { me.should eq repo }
39
+ end
40
+ end
41
+
42
+ context "branch" do
43
+ it_should_behave_like "an entity" do
44
+ Given(:entity) { TFSGraph::Branch.new(repo, name: "Demo", created: Time.now) }
45
+
46
+ context "has properties" do
47
+ Then { entity.name.should == "Demo" }
48
+ And { entity.archived.should == "false" }
49
+ And { entity.created.should be_a Time }
50
+ end
51
+ end
52
+
53
+ context "time converter" do
54
+ Given(:time) { Time.now }
55
+
56
+ context "can rebuild time from unixtime" do
57
+ When(:entity) { TFSGraph::Branch.new(repo, name: "Demo", created: time.to_i) }
58
+ Then { entity.created.to_i.should eq(time.to_i) }
59
+ end
60
+
61
+ context "can rebuild time from Time" do
62
+ When(:entity) { TFSGraph::Branch.new(repo, name: "Demo", created: time) }
63
+ Then { entity.created.to_i.should eq(time.to_i) }
64
+ end
65
+ end
66
+ end
67
+
68
+ context "changeset" do
69
+ it_should_behave_like "an entity" do
70
+ Given(:entity) { TFSGraph::Changeset.new(repo, committer: "James") }
71
+
72
+ context "has properties" do
73
+ Then { entity.committer.should == "James" }
74
+ And { entity.branch_path.should be_nil }
75
+ And { entity.comment.should be_nil }
76
+ end
77
+ end
78
+ end
79
+
80
+ context "project" do
81
+ it_should_behave_like "an entity" do
82
+ Given(:entity) { TFSGraph::Project.new(repo, name: "FooBarge") }
83
+
84
+ context "has properties" do
85
+ Then { entity.name.should == "FooBarge" }
86
+ And { entity.last_updated.should eq(Time.at(0).utc) }
87
+ end
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ require 'tfs_graph/project'
4
+
5
+ describe TFSGraph::Project do
6
+ Given(:repo) { flexmock("FakeRepository") }
7
+ Given(:project) { TFSGraph::Project.new(repo, {name: "Fake Project"}) }
8
+
9
+ context "last updated is not available if never updated" do
10
+ Then { project.last_updated.should == Time.at(0).utc }
11
+ end
12
+
13
+ context "last updated is a date if set" do
14
+ Given(:time) { Time.now }
15
+ Given(:project) { TFSGraph::Project.new(repo, {name: "Fake Project", last_updated: time }) }
16
+ Then { project.last_updated.should == time }
17
+ end
18
+
19
+ context "can set last updated" do
20
+ before { Timecop.freeze }
21
+ after { Timecop.return }
22
+
23
+ Given(:project) { TFSGraph::Project.new(repo, {name: "Fake Project"}) }
24
+ Given { repo.should_receive(:save).with(project).and_return { project.persist 1, flexmock(id: 1) }}
25
+ When { project.updated! }
26
+ Then { project.last_updated.should eq(Time.now.utc) }
27
+ And { project.should be_persisted }
28
+ end
29
+ end
@@ -0,0 +1,328 @@
1
+ require 'spec_helper'
2
+
3
+ require 'tfs_graph/repository/related_repository'
4
+ require 'tfs_graph/server_registry'
5
+ require 'tfs_graph/repository_registry'
6
+
7
+ require 'tfs_graph/associators/changeset_tree_builder'
8
+ require 'tfs_graph/changeset_merge'
9
+
10
+ # Integration testing between:
11
+ # - different repos
12
+ # - the registry
13
+ # - objects the repo returns
14
+
15
+ describe "Related repo integration" do
16
+ before :all do
17
+ TFSGraph::ServerRegistry.register {|r| r.redis url: "redis://localhost:6379", namespace: "test" }
18
+ end
19
+
20
+ after(:each) do
21
+ TFSGraph::ServerRegistry.server.drop_all
22
+ end
23
+
24
+ Given(:register) { TFSGraph::RepositoryRegistry.register {|r| r.type TFSGraph::Repository::RelatedRepository }}
25
+ Given(:project_repo) { register.project_repository }
26
+ Given { 3.times {|i| project_repo.create(name: "TestProject_#{i}") }}
27
+ Given { 2.times {|i| project_repo.create(name: "TestProject_#{i+7}", hidden: true) }}
28
+ Given(:foo) { project_repo.create(name: "TestProject_Foo") }
29
+
30
+ context "project lookups" do
31
+ context "can lookup all projects" do
32
+ When(:all) { project_repo.all }
33
+ Then { all.count.should == 5 }
34
+ And { all.all? {|p| p.is_a? TFSGraph::Project }.should be_true }
35
+ end
36
+
37
+ context "can lookup active projects only" do
38
+ When(:all) { project_repo.active }
39
+ Then { all.count.should == 3 }
40
+ end
41
+
42
+ context "can lookup by id" do
43
+ When(:project) { project_repo.find foo.id }
44
+ Then { project.should == foo }
45
+ end
46
+
47
+ context "can lookup project by name" do
48
+ When(:project) { project_repo.find_by_name foo.name }
49
+ Then { project.name.should == foo.name }
50
+ end
51
+
52
+ context "throws not found error if id not found" do
53
+ When(:result) { project_repo.find 123 }
54
+ Then { result.should have_failed(TFSGraph::Repository::NotFound)}
55
+ end
56
+
57
+ context "throws not found error if name found" do
58
+ When(:result) { project_repo.find "FakeProject" }
59
+ Then { result.should have_failed(TFSGraph::Repository::NotFound)}
60
+ end
61
+ end
62
+
63
+ context "branches" do
64
+ Given(:branch_repo) { register.branch_repository }
65
+ Given { 3.times do |i|
66
+ branch = branch_repo.create(path: "$/Root/Branch-#{i}", original_path: "$/Root/Branch-#{i}")
67
+ foo.add_branch(branch)
68
+ end
69
+ }
70
+
71
+ context "can find project for branch" do
72
+ Given(:branch) {
73
+ branch_repo.create(
74
+ path: "$/Root/Branch-Base",
75
+ original_path: "$/Root/Branch-Base",
76
+ project: "TestProject_Foo"
77
+ )
78
+ }
79
+ When(:project) { branch_repo.project_for_branch branch }
80
+ Then { project.should eq(foo) }
81
+ end
82
+
83
+ context "branch lookups through a project" do
84
+ When(:branches) { foo.branches }
85
+ Then { branches.size.should eq(3) }
86
+ And { branches.all? {|p| p.is_a? TFSGraph::Branch }.should be_true }
87
+ end
88
+
89
+ context "can get specific branch for a project by path" do
90
+ When(:branch) { branch_repo.find_in_project(foo, "$/Root/Branch-1") }
91
+ Then { branch.should_not be_nil }
92
+ And { branch.path.should eq("$/Root/Branch-1") }
93
+ end
94
+
95
+ context "project's branches" do
96
+ Given(:archived_branch) {
97
+ branch_repo.create(
98
+ path: "$/Root/Branch-Base",
99
+ original_path: "$/Root/Archived/Branch-Base",
100
+ project: "TestProject_Foo",
101
+ )
102
+ }
103
+ Given(:hidden_branch) {
104
+ branch_repo.create(
105
+ path: "$/Root/Branch-Base",
106
+ original_path: "$/Root/Branch-Boot",
107
+ project: "TestProject_Foo",
108
+ hidden: true
109
+ )
110
+ }
111
+ Given { foo.add_branch(archived_branch) }
112
+ Given { foo.add_branch(hidden_branch) }
113
+
114
+ context "active branches for a project" do
115
+ When(:active) { foo.active_branches }
116
+ Then { active.size.should eq(3) }
117
+ end
118
+
119
+ context "all non-hidden branches for a project" do
120
+ When(:visible) { foo.branches }
121
+ Then { visible.size.should eq(4) }
122
+ end
123
+
124
+ context "all with hidden" do
125
+ When(:all) { foo.branches_with_hidden }
126
+ Then { all.size.should eq(5) }
127
+ end
128
+ end
129
+
130
+ shared_examples "branch type" do |type, name, root|
131
+ Given { TFSGraph::ServerRegistry.redis.flushall }
132
+ Given(:normal) {
133
+ branch_repo.create(
134
+ path: "$/Root/#{name}",
135
+ original_path: "$/Root/#{name}",
136
+ root: root,
137
+ name: name
138
+ )
139
+ }
140
+ Given(:archived) {
141
+ branch_repo.create(
142
+ path: "$/Root/#{name}",
143
+ original_path: "$/Root/Archived/#{name}",
144
+ root: root,
145
+ name: name
146
+ )
147
+ }
148
+ Given(:hidden) {
149
+ branch_repo.create(
150
+ path: "$/Root/#{name}",
151
+ original_path: "$/Root/#{name}",
152
+ root: root,
153
+ name: name,
154
+ hidden: true
155
+ )
156
+ }
157
+ Given { foo.add_branch(normal) }
158
+ Given { foo.add_branch(archived) }
159
+ Given { foo.add_branch(hidden) }
160
+
161
+ context "can find the #{type}s" do
162
+ When(:results) { foo.send "#{type}s" }
163
+ Then { results.size.should eq(2) }
164
+ end
165
+
166
+ context "can find the hidden #{type}s" do
167
+ When(:results) { foo.send "#{type}s_with_hidden" }
168
+ Then { results.size.should eq(3) }
169
+ end
170
+
171
+ context "can find the archived #{type}s" do
172
+ When(:results) { foo.send "archived_#{type}s" }
173
+ Then { results.size.should eq(1) }
174
+ end
175
+ end
176
+
177
+ context "can get the master branches" do
178
+ it_should_behave_like "branch type", "master", "Branch-Cool", ""
179
+ end
180
+
181
+ context "can get the release branches" do
182
+ it_should_behave_like "branch type", "release", "Branch-R22-1234", "Branch-Cool"
183
+ end
184
+
185
+ context "can get the feature" do
186
+ it_should_behave_like "branch type", "feature", "Branch-Base-Boot", "Branch-Cool"
187
+ end
188
+
189
+ context "changeset lookups" do
190
+ Given(:cs_repo) { register.changeset_repository }
191
+ Given(:branch) { foo.branches.first }
192
+ Given!(:changesets) {
193
+ 3.times.map do |i|
194
+ cs = cs_repo.create(comment: "Never gonna let you down.", id: "123#{i}".to_i, committer: "John Gray the #{i}th", created: i.days.ago)
195
+ branch.add_changeset(cs)
196
+ cs
197
+ end
198
+ }
199
+ Given!(:noise) {
200
+ # some extra noise
201
+ 3.times.map do |i|
202
+ cs = cs_repo.create(comment: "Never gonna give you up.", id: "323#{i}".to_i, commiter: "Jim Beam", created: i.days.ago)
203
+ foo.branches[1].add_changeset(cs)
204
+ cs
205
+ end
206
+ }
207
+ Given { TFSGraph::ChangesetTreeBuilder.to_tree branch, changesets }
208
+
209
+ context "paths are set" do
210
+ When(:cs) { branch.changesets }
211
+ Then { cs.map(&:branch_path).all? {|path| path == branch.path }.should be_true }
212
+ And { cs.all? {|b| b.is_a? TFSGraph::Changeset }.should be_true }
213
+ end
214
+
215
+ context "from a project" do
216
+ context "all" do
217
+ When(:activity) { foo.all_activity }
218
+ Then { activity.size.should == 6 }
219
+ And { expect(activity).to match_array(noise.concat(changesets)) }
220
+ end
221
+
222
+ context "all_activity_by_date" do
223
+ When(:activity) { foo.all_activity_by_date(0.5.days.ago) }
224
+ Then { activity.values.flatten.size.should == 2 }
225
+ And { expect(activity.values.flatten.map(&:id)).to match_array([3230, 1230]) }
226
+ end
227
+ end
228
+
229
+ context "from a branch" do
230
+ context "branch accessors" do
231
+ When(:authors) { branch.contributors }
232
+ Then { expect(authors.keys).to match_array(["John Gray the 0th", "John Gray the 1th", "John Gray the 2th"]) }
233
+ end
234
+
235
+ context "as a tree" do
236
+
237
+ context "branch can get it's root node" do
238
+ When(:root) { branch.root_changeset }
239
+ Then { root.id.should eq(1230) }
240
+ end
241
+
242
+ context "can get it's last node" do
243
+ When(:last) { branch.last_changeset }
244
+ Then { last.id.should eq(1232) }
245
+ end
246
+ end
247
+ end
248
+
249
+ context "within changesets" do
250
+ Given(:changeset) { changesets.first }
251
+
252
+ context "can walk the chain" do
253
+ Given(:results) { [] }
254
+ When {
255
+ child = changeset.next
256
+ loop do
257
+ results << child.id
258
+ child = child.next
259
+ end
260
+ }
261
+ Then { results.should match_array([1231, 1232])}
262
+ end
263
+
264
+ context "can get branch" do
265
+ When(:cs_branch) { changeset.branch }
266
+ Then { cs_branch.should eq(branch) }
267
+ end
268
+ end
269
+
270
+ context "with merges" do
271
+ Given(:merge_attrs) {[
272
+ {source_version: 1230, target_version: 3230},
273
+ {source_version: 1231, target_version: 3231},
274
+ {source_version: 1232, target_version: 3231}
275
+ ]}
276
+ Given { merge_attrs.each {|attrs| TFSGraph::ChangesetMerge.create attrs }}
277
+
278
+ context "parentage" do
279
+ Given(:child) { foo.branches[1] }
280
+ Given { child.root = branch.path; child.send :detect_type; child.save! }
281
+
282
+ Then { branch.should be_master }
283
+
284
+ context "related branches" do
285
+ When(:related) { child.related_branches }
286
+ Then { related.size.should eq(1) }
287
+ And { related.first.should == branch.id }
288
+ end
289
+
290
+ context "json reports related branches" do
291
+ When(:data) { JSON.parse child.to_json, symbolize_names: true }
292
+ Then { data[:related_branches].size.should eq(1) }
293
+ And { data[:related_branches].should match_array([branch.id]) }
294
+ end
295
+
296
+ context "get absolute root" do
297
+ When(:root) { child.absolute_root }
298
+ Then { root.should == branch }
299
+ end
300
+
301
+ context "ahead stats" do
302
+ When(:ahead) { child.ahead_of_master }
303
+ Then { ahead.should eq(1) }
304
+ end
305
+
306
+ context "behind stats" do
307
+ When(:behind) { child.behind_master }
308
+ Then { behind.should eq(0) }
309
+ end
310
+ end
311
+
312
+ context "merged changesets" do
313
+ Given(:changeset) { cs_repo.find(1230) }
314
+ When(:merges) { changeset.merged }
315
+ Then { merges.size.should eq(1) }
316
+ And { merges.map(&:id).should match_array([3230]) }
317
+ end
318
+
319
+ context "merges changesets" do
320
+ Given(:changeset) { cs_repo.find(3231) }
321
+ When(:merges) { changeset.merges }
322
+ Then { merges.size.should eq(2) }
323
+ And { merges.map(&:id).should match_array([1232, 1231]) }
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ require "tfs_graph/branch"
4
+ require "tfs_graph/changeset"
5
+ require "tfs_graph/project"
6
+
7
+ require 'tfs_graph/repository'
8
+ require 'tfs_graph/repository_registry'
9
+
10
+ describe TFSGraph::RepositoryRegistry do
11
+ Given(:repo) { flexmock(TFSGraph::Repository) }
12
+ Given(:register) { TFSGraph::RepositoryRegistry.register {|r|
13
+ r.type repo
14
+ }}
15
+
16
+ def constantize(string)
17
+ Object.const_get(string)
18
+ end
19
+
20
+ class TFSGraph::Behaviors::Repository
21
+ module Branch; end
22
+ module Project; end
23
+ module Changeset; end
24
+ end
25
+
26
+ shared_examples "a repository builder" do |type|
27
+ Given {
28
+ repo.should_receive(:new).
29
+ with(constantize("TFSGraph::#{type.capitalize}")).pass_thru
30
+ }
31
+ When(:entity_repo) { register.send "#{type}_repository" }
32
+ Then { entity_repo.should be_a(TFSGraph::Repository) }
33
+ And { register.instance_variable_get("@#{type}_repo").should_not be_nil }
34
+ And { register.send("#{type}_repository").should == entity_repo }
35
+ end
36
+
37
+ context "Branch" do
38
+ it_should_behave_like "a repository builder", "branch"
39
+ end
40
+
41
+ context "Changeset" do
42
+ it_should_behave_like "a repository builder", "changeset"
43
+ end
44
+
45
+ context "Project" do
46
+ it_should_behave_like "a repository builder", "project"
47
+ end
48
+ end