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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Gemfile +12 -4
- data/Rakefile +1 -0
- data/lib/tfs_graph.rb +1 -2
- data/lib/tfs_graph/abstract_store.rb +23 -0
- data/lib/tfs_graph/associators/branch_associator.rb +1 -1
- data/lib/tfs_graph/associators/changeset_tree_builder.rb +29 -0
- data/lib/tfs_graph/behaviors.rb +9 -0
- data/lib/tfs_graph/behaviors/neo4j_repository/branch.rb +39 -0
- data/lib/tfs_graph/behaviors/neo4j_repository/changeset.rb +12 -0
- data/lib/tfs_graph/behaviors/neo4j_repository/project.rb +89 -0
- data/lib/tfs_graph/behaviors/related_repository/branch.rb +26 -0
- data/lib/tfs_graph/behaviors/related_repository/changeset.rb +8 -0
- data/lib/tfs_graph/behaviors/related_repository/project.rb +48 -0
- data/lib/tfs_graph/branch.rb +84 -37
- data/lib/tfs_graph/branch/branch_archive_handler.rb +10 -6
- data/lib/tfs_graph/branch/branch_store.rb +13 -26
- data/lib/tfs_graph/changeset.rb +46 -25
- data/lib/tfs_graph/changeset/changeset_normalizer.rb +1 -0
- data/lib/tfs_graph/changeset/changeset_store.rb +13 -36
- data/lib/tfs_graph/changeset_merge.rb +20 -18
- data/lib/tfs_graph/changeset_merge/changeset_merge_store.rb +13 -10
- data/lib/tfs_graph/config.rb +12 -4
- data/lib/tfs_graph/entity.rb +34 -6
- data/lib/tfs_graph/extensions.rb +27 -0
- data/lib/tfs_graph/graph_populator.rb +9 -1
- data/lib/tfs_graph/persistable_entity.rb +60 -0
- data/lib/tfs_graph/populators/everything.rb +16 -4
- data/lib/tfs_graph/populators/for_archived_branch.rb +28 -0
- data/lib/tfs_graph/populators/for_branch.rb +35 -0
- data/lib/tfs_graph/populators/for_project.rb +22 -5
- data/lib/tfs_graph/populators/since_date.rb +21 -5
- data/lib/tfs_graph/populators/since_last.rb +22 -10
- data/lib/tfs_graph/populators/utilities.rb +4 -19
- data/lib/tfs_graph/project.rb +49 -13
- data/lib/tfs_graph/project/project_store.rb +13 -22
- data/lib/tfs_graph/repository.rb +78 -0
- data/lib/tfs_graph/repository/neo4j_repository.rb +97 -0
- data/lib/tfs_graph/repository/related_repository.rb +89 -0
- data/lib/tfs_graph/repository_registry.rb +60 -0
- data/lib/tfs_graph/server_registry.rb +45 -0
- data/lib/tfs_graph/store_helpers.rb +4 -5
- data/lib/tfs_graph/version.rb +1 -1
- data/schema.cypher +7 -0
- data/spec/branch_spec.rb +120 -0
- data/spec/neo4j_repository_integration_spec.rb +346 -0
- data/spec/persistable_entity_spec.rb +91 -0
- data/spec/project_spec.rb +29 -0
- data/spec/related_repository_integration_spec.rb +328 -0
- data/spec/repository_registry_spec.rb +48 -0
- data/spec/repository_spec.rb +73 -0
- data/spec/server_registery_spec.rb +36 -0
- data/spec/spec_helper.rb +12 -24
- data/tfs_graph.gemspec +3 -2
- metadata +67 -21
- data/lib/tfs_graph/associators/changeset_tree_creator.rb +0 -19
- data/spec/factories.rb +0 -20
@@ -7,16 +7,20 @@ module TFSGraph
|
|
7
7
|
# is fairly useless, we'll hide it in favor of the "ghost" branch.
|
8
8
|
class << self
|
9
9
|
def hide_all_archives
|
10
|
-
|
10
|
+
RepositoryRegistry.project_repository.all.map {|project| hide_moved_archives_for_project(project) }
|
11
11
|
end
|
12
12
|
|
13
13
|
def hide_moved_archives_for_project(project)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
group.
|
14
|
+
project.branches.group_by(&:path).map do |path, group|
|
15
|
+
next unless group.size > 1
|
16
|
+
|
17
|
+
group.each do |branch|
|
18
|
+
branch.hide! if branch.archived?
|
19
|
+
branch.archive! unless branch.archived?
|
20
|
+
end
|
21
|
+
|
22
|
+
group
|
18
23
|
end
|
19
|
-
archived
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -1,53 +1,40 @@
|
|
1
|
-
require 'tfs_graph/
|
2
|
-
require 'tfs_graph/tfs_helpers'
|
3
|
-
require 'tfs_graph/store_helpers'
|
1
|
+
require 'tfs_graph/abstract_store'
|
4
2
|
|
5
3
|
require 'tfs_graph/branch/branch_normalizer'
|
6
4
|
require 'tfs_graph/branch'
|
7
5
|
|
8
6
|
module TFSGraph
|
9
|
-
class BranchStore
|
10
|
-
include TFSClient
|
11
|
-
include TFSHelpers
|
12
|
-
include StoreHelpers
|
13
|
-
|
7
|
+
class BranchStore < AbstractStore
|
14
8
|
LIMIT = 1000
|
15
9
|
|
16
10
|
def initialize(project)
|
17
11
|
@project = project
|
18
12
|
end
|
19
13
|
|
20
|
-
def
|
21
|
-
|
14
|
+
def fetch_since_last_update
|
15
|
+
fetch_since_date(@project.last_updated.iso8601)
|
22
16
|
end
|
23
17
|
|
24
|
-
def
|
25
|
-
|
18
|
+
def fetch_since_date(date)
|
19
|
+
normalize root_query.where("DateCreated gt DateTime'#{date}'").run
|
26
20
|
end
|
27
21
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
22
|
+
def cache(attrs)
|
23
|
+
branch = RepositoryRegistry.branch_repository.build attrs
|
24
|
+
|
25
|
+
# add_branch action runs save! on branch
|
26
|
+
@project.add_branch(branch)
|
31
27
|
|
32
|
-
|
33
|
-
normalize root_query.where("DateCreated gt DateTime'#{last_updated_on.iso8601}'").run
|
28
|
+
branch
|
34
29
|
end
|
35
30
|
|
36
31
|
private
|
37
32
|
def root_query
|
38
|
-
tfs.projects(@project.name).branches.limit(LIMIT)
|
33
|
+
tfs.projects(@project.name).branches.order_by('DateCreated desc').limit(LIMIT)
|
39
34
|
end
|
40
35
|
|
41
36
|
def normalize(branches)
|
42
37
|
BranchNormalizer.normalize_many branches
|
43
38
|
end
|
44
|
-
|
45
|
-
def persist(branches)
|
46
|
-
branches.map do |branch_attrs|
|
47
|
-
branch = Branch.create branch_attrs
|
48
|
-
Related::Relationship.create(:branches, @project, branch)
|
49
|
-
branch
|
50
|
-
end
|
51
|
-
end
|
52
39
|
end
|
53
40
|
end
|
data/lib/tfs_graph/changeset.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
|
-
require 'tfs_graph/
|
1
|
+
require 'tfs_graph/persistable_entity'
|
2
2
|
require 'tfs_graph/tfs_helpers'
|
3
3
|
|
4
4
|
# FIXME: DRY along side the Branch class
|
5
5
|
module TFSGraph
|
6
|
-
class Changeset <
|
6
|
+
class Changeset < PersistableEntity
|
7
7
|
extend TFSHelpers
|
8
|
-
extend Comparable
|
9
8
|
|
10
9
|
SCHEMA = {
|
11
10
|
comment: {key: "Comment", type: String},
|
12
11
|
committer: {key: "Committer", converter: ->(name) { base_username(name) }, type: String},
|
13
|
-
created: {key: "CreationDate", type:
|
12
|
+
created: {key: "CreationDate", type: Time},
|
14
13
|
id: {key: "Id", type: Integer},
|
15
14
|
branch_path: {type: String, default: nil},
|
16
|
-
tags: {type: Array, default: []},
|
17
|
-
parent: {type: Integer, default:
|
18
|
-
merge_parent: {type: Integer, default:
|
15
|
+
# tags: {type: Array, default: []},
|
16
|
+
parent: {type: Integer, default: 0},
|
17
|
+
merge_parent: {type: Integer, default: 0}
|
19
18
|
}
|
20
19
|
|
21
20
|
act_as_entity
|
@@ -24,14 +23,45 @@ module TFSGraph
|
|
24
23
|
id <=> other.id
|
25
24
|
end
|
26
25
|
|
26
|
+
# override for the & (intersect) operator
|
27
|
+
def eql?(other)
|
28
|
+
other.is_a?(self.class) && other == self
|
29
|
+
end
|
30
|
+
|
31
|
+
def hash
|
32
|
+
@internal_id.hash
|
33
|
+
end
|
34
|
+
|
35
|
+
def id
|
36
|
+
@id.to_i unless @id.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge?
|
40
|
+
!base? && @merge_parent != 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def base?
|
44
|
+
@parent == 0 || @parent == @merge_parent
|
45
|
+
end
|
46
|
+
|
47
|
+
def created
|
48
|
+
return nil unless @created
|
49
|
+
return @created unless @created.is_a? String
|
50
|
+
@created = Time.parse @created
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_child(changeset)
|
54
|
+
@repo.relate(:child, self.db_object, changeset.db_object)
|
55
|
+
end
|
56
|
+
|
27
57
|
def next
|
28
|
-
child =
|
58
|
+
child = @repo.get_nodes(db_object, :outgoing, :child, self.class).first
|
29
59
|
raise StopIteration unless child
|
30
60
|
child
|
31
61
|
end
|
32
62
|
|
33
63
|
def branch
|
34
|
-
|
64
|
+
@repo.get_nodes(db_object, :incoming, :changesets, Branch).first
|
35
65
|
end
|
36
66
|
|
37
67
|
def formatted_created
|
@@ -39,8 +69,9 @@ module TFSGraph
|
|
39
69
|
end
|
40
70
|
|
41
71
|
%w(merges merged).each do |type|
|
72
|
+
directon = (type == "merges") ? :outgoing : :incoming
|
42
73
|
define_method type do
|
43
|
-
|
74
|
+
@repo.get_nodes(db_object, directon, :merges, self.class)
|
44
75
|
end
|
45
76
|
|
46
77
|
define_method "#{type}_ids" do
|
@@ -49,23 +80,13 @@ module TFSGraph
|
|
49
80
|
end
|
50
81
|
|
51
82
|
def as_json(options={})
|
52
|
-
|
53
|
-
super
|
54
|
-
end
|
83
|
+
results = super
|
55
84
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
def set_merging_from
|
62
|
-
from = merges.max
|
63
|
-
self.merge_parent = from.id if from
|
64
|
-
end
|
85
|
+
[:merges_ids, :merged_ids].each do |key|
|
86
|
+
results[key] = self.send key
|
87
|
+
end
|
65
88
|
|
66
|
-
|
67
|
-
def get_merges_for(merge)
|
68
|
-
merge.options(model: self.class).nodes.to_a
|
89
|
+
results
|
69
90
|
end
|
70
91
|
end
|
71
92
|
end
|
@@ -1,65 +1,42 @@
|
|
1
|
-
require 'tfs_graph/
|
2
|
-
require 'tfs_graph/store_helpers'
|
1
|
+
require 'tfs_graph/abstract_store'
|
3
2
|
|
4
3
|
require 'tfs_graph/changeset/changeset_normalizer'
|
5
4
|
require 'tfs_graph/changeset'
|
5
|
+
|
6
6
|
# Wraps domain knowledge of changeset TFS access
|
7
7
|
|
8
8
|
module TFSGraph
|
9
|
-
class ChangesetStore
|
10
|
-
include TFSClient
|
11
|
-
include StoreHelpers
|
12
|
-
|
9
|
+
class ChangesetStore < AbstractStore
|
13
10
|
LIMIT = 10000
|
14
11
|
|
15
12
|
def initialize(branch)
|
16
13
|
@branch = branch
|
17
14
|
end
|
18
15
|
|
19
|
-
def
|
20
|
-
|
16
|
+
def fetch_since_last_update
|
17
|
+
fetch_since_date(@branch.last_updated.iso8601)
|
21
18
|
end
|
22
19
|
|
23
|
-
def
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
def cache_since_date(start)
|
28
|
-
persist since_date(start)
|
20
|
+
def fetch_since_date(date)
|
21
|
+
normalize root_query.where("CreationDate gt DateTime'#{date}'").run
|
29
22
|
end
|
30
23
|
|
31
|
-
def
|
32
|
-
|
33
|
-
end
|
24
|
+
def cache(attrs)
|
25
|
+
changeset = RepositoryRegistry.changeset_repository.build attrs
|
34
26
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
27
|
+
# add_changeset action runs save! on changeset
|
28
|
+
@branch.add_changeset changeset
|
38
29
|
|
39
|
-
|
40
|
-
since_date(last_updated_on.iso8601)
|
30
|
+
changeset
|
41
31
|
end
|
42
32
|
|
43
33
|
private
|
44
34
|
def root_query
|
45
|
-
tfs.branches(@branch.path).changesets.limit(LIMIT)
|
35
|
+
tfs.branches(@branch.path).changesets.order_by("Id asc").limit(LIMIT)
|
46
36
|
end
|
47
37
|
|
48
38
|
def normalize(changesets)
|
49
39
|
ChangesetNormalizer.normalize_many changesets, @branch.path
|
50
40
|
end
|
51
|
-
|
52
|
-
def persist(changesets)
|
53
|
-
changesets.map do |attrs|
|
54
|
-
begin
|
55
|
-
changeset = Changeset.create attrs
|
56
|
-
Related::Relationship.create :changesets, @branch, changeset
|
57
|
-
changeset
|
58
|
-
rescue Related::ValidationsFailed => ex
|
59
|
-
# puts ex.message
|
60
|
-
next
|
61
|
-
end
|
62
|
-
end.compact
|
63
|
-
end
|
64
41
|
end
|
65
42
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'tfs_graph/entity'
|
2
1
|
require 'tfs_graph/changeset'
|
3
2
|
|
4
3
|
module TFSGraph
|
@@ -6,8 +5,7 @@ module TFSGraph
|
|
6
5
|
|
7
6
|
SCHEMA = {
|
8
7
|
target_version: {key: "TargetVersion", type: Integer},
|
9
|
-
source_version: {key: "SourceVersion", type: Integer}
|
10
|
-
branch: {default: nil, type: String}
|
8
|
+
source_version: {key: "SourceVersion", type: Integer}
|
11
9
|
}
|
12
10
|
|
13
11
|
act_as_entity
|
@@ -18,40 +16,44 @@ module TFSGraph
|
|
18
16
|
begin
|
19
17
|
merge = new(attrs)
|
20
18
|
|
21
|
-
# this will throw an error if one of the relations is not found
|
22
|
-
# this is the desired condition as it will throw out the merge if there aren't two endpoints found
|
23
19
|
target, source = merge.get_relations
|
20
|
+
return nil unless target.persisted? and source.persisted?
|
24
21
|
|
25
|
-
|
22
|
+
merge.join :merges, target, source
|
26
23
|
|
27
24
|
# relate the branches as well
|
28
|
-
|
25
|
+
if source.branch && target.branch
|
26
|
+
merge.join :related, source.branch, target.branch
|
29
27
|
|
30
|
-
|
31
|
-
|
28
|
+
merge.join :included, source.branch, target
|
29
|
+
merge.join :included, target.branch, source
|
30
|
+
end
|
32
31
|
|
33
32
|
merge
|
34
|
-
rescue
|
33
|
+
rescue TFSGraph::Repository::NotFound => ex
|
35
34
|
# puts "Could not find a changeset to merge with: #{ex.message}"
|
36
|
-
rescue Related::ValidationsFailed => ex
|
37
|
-
# puts "Couldn't create relationship for #{merge.source_version} to #{merge.target_version}"
|
38
35
|
end
|
39
36
|
end
|
40
37
|
|
41
|
-
def save
|
42
|
-
# nothing, no need to save
|
43
|
-
end
|
44
|
-
|
45
38
|
def get_relations
|
46
39
|
return get_target, get_source
|
47
40
|
end
|
48
41
|
|
49
42
|
def get_source
|
50
|
-
|
43
|
+
repo.find(source_version)
|
51
44
|
end
|
52
45
|
|
53
46
|
def get_target
|
54
|
-
|
47
|
+
repo.find(target_version)
|
48
|
+
end
|
49
|
+
|
50
|
+
def join(relation, target, source)
|
51
|
+
repo.relate(relation, target.db_object, source.db_object)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def repo
|
56
|
+
@repo ||= RepositoryRegistry.changeset_repository
|
55
57
|
end
|
56
58
|
end
|
57
59
|
end
|
@@ -1,24 +1,27 @@
|
|
1
|
-
require 'tfs_graph/
|
1
|
+
require 'tfs_graph/abstract_store'
|
2
|
+
|
2
3
|
require 'tfs_graph/changeset_merge/changeset_merge_normalizer'
|
3
4
|
require 'tfs_graph/changeset_merge'
|
4
5
|
|
5
6
|
module TFSGraph
|
6
|
-
class ChangesetMergeStore
|
7
|
-
include TFSClient
|
8
|
-
|
7
|
+
class ChangesetMergeStore < AbstractStore
|
9
8
|
LIMIT = 10000
|
10
9
|
|
11
10
|
def initialize(branch)
|
12
11
|
@branch = branch
|
13
12
|
end
|
14
13
|
|
15
|
-
def cache
|
16
|
-
|
17
|
-
|
14
|
+
def cache(attrs)
|
15
|
+
ChangesetMerge.create(attrs)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def root_query
|
20
|
+
tfs.branches(@branch.path).changesetmerges.limit(LIMIT)
|
21
|
+
end
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
end.compact
|
23
|
+
def normalize(merges)
|
24
|
+
ChangesetMergeNormalizer.normalize_many merges, @branch
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
data/lib/tfs_graph/config.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
module TFSGraph
|
2
2
|
class Config
|
3
|
-
attr_accessor :tfs
|
4
|
-
attr_reader :redis
|
3
|
+
attr_accessor :tfs, :graph
|
5
4
|
|
6
|
-
def redis
|
7
|
-
|
5
|
+
def redis(url: url, namespace: namespace)
|
6
|
+
ServerRegistry.register do |r|
|
7
|
+
r.redis url: url, namespace: namespace
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def graph(repo_type: nil)
|
12
|
+
raise ArgumentError unless repo_type
|
13
|
+
RepositoryRegistry.register do |r|
|
14
|
+
r.type repo_type
|
15
|
+
end
|
8
16
|
end
|
9
17
|
end
|
10
18
|
end
|
data/lib/tfs_graph/entity.rb
CHANGED
@@ -1,16 +1,44 @@
|
|
1
1
|
module TFSGraph
|
2
|
-
class Entity
|
2
|
+
class Entity
|
3
3
|
def self.inherited(klass)
|
4
4
|
define_singleton_method :act_as_entity do
|
5
|
-
klass::SCHEMA.
|
6
|
-
property key, details[:type]
|
7
|
-
end
|
5
|
+
attr_accessor *klass::SCHEMA.keys
|
8
6
|
end
|
9
7
|
end
|
10
8
|
|
11
|
-
|
9
|
+
def initialize(args)
|
10
|
+
schema.each do |key, details|
|
11
|
+
value = (args[key] || details[:default])
|
12
|
+
|
13
|
+
value = ressurect_time(value) if details[:type] == Time
|
14
|
+
|
15
|
+
send "#{key}=", value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
hash = {}
|
21
|
+
schema.keys.each do |key|
|
22
|
+
hash[key] = send key
|
23
|
+
end
|
24
|
+
|
25
|
+
hash.each do |k,v|
|
26
|
+
next unless v.is_a? Time
|
27
|
+
hash[k] = v.utc.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
alias_method :attributes, :to_hash
|
33
|
+
|
12
34
|
def schema
|
13
35
|
self.class::SCHEMA
|
14
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def ressurect_time(time)
|
40
|
+
return time if (time.is_a?(Time) || time.nil?)
|
41
|
+
Time::at time.to_i
|
42
|
+
end
|
15
43
|
end
|
16
|
-
end
|
44
|
+
end
|