tfs_graph 0.1.1
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 +7 -0
- data/.gitignore +20 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +1 -0
- data/lib/tfs_graph/associators/branch_associator.rb +25 -0
- data/lib/tfs_graph/associators/changeset_tree_creator.rb +19 -0
- data/lib/tfs_graph/branch/branch_archive_handler.rb +23 -0
- data/lib/tfs_graph/branch/branch_normalizer.rb +11 -0
- data/lib/tfs_graph/branch/branch_store.rb +53 -0
- data/lib/tfs_graph/branch.rb +157 -0
- data/lib/tfs_graph/changeset/changeset_normalizer.rb +21 -0
- data/lib/tfs_graph/changeset/changeset_store.rb +65 -0
- data/lib/tfs_graph/changeset.rb +71 -0
- data/lib/tfs_graph/changeset_merge/changeset_merge_normalizer.rb +21 -0
- data/lib/tfs_graph/changeset_merge/changeset_merge_store.rb +24 -0
- data/lib/tfs_graph/changeset_merge.rb +57 -0
- data/lib/tfs_graph/config.rb +10 -0
- data/lib/tfs_graph/entity.rb +16 -0
- data/lib/tfs_graph/graph_populator.rb +35 -0
- data/lib/tfs_graph/normalizer.rb +30 -0
- data/lib/tfs_graph/populators/everything.rb +20 -0
- data/lib/tfs_graph/populators/for_project.rb +18 -0
- data/lib/tfs_graph/populators/since_date.rb +26 -0
- data/lib/tfs_graph/populators/since_last.rb +26 -0
- data/lib/tfs_graph/populators/utilities.rb +38 -0
- data/lib/tfs_graph/populators.rb +11 -0
- data/lib/tfs_graph/project/project_normalizer.rb +12 -0
- data/lib/tfs_graph/project/project_store.rb +30 -0
- data/lib/tfs_graph/project.rb +59 -0
- data/lib/tfs_graph/store_helpers.rb +31 -0
- data/lib/tfs_graph/tfs_client.rb +37 -0
- data/lib/tfs_graph/tfs_helpers.rb +42 -0
- data/lib/tfs_graph/version.rb +3 -0
- data/lib/tfs_graph.rb +19 -0
- data/spec/factories.rb +20 -0
- data/spec/helpers_spec.rb +48 -0
- data/spec/spec_helper.rb +43 -0
- data/tfs_graph.gemspec +26 -0
- metadata +144 -0
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'tfs_graph/entity'
         | 
| 2 | 
            +
            require 'tfs_graph/changeset'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TFSGraph
         | 
| 5 | 
            +
              class ChangesetMerge < Entity
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                SCHEMA = {
         | 
| 8 | 
            +
                  target_version: {key: "TargetVersion", type: Integer},
         | 
| 9 | 
            +
                  source_version: {key: "SourceVersion", type: Integer},
         | 
| 10 | 
            +
                  branch: {default: nil, type: String}
         | 
| 11 | 
            +
                }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                act_as_entity
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # overwrite the creator, and create a relationship between the
         | 
| 16 | 
            +
                # two changesets requested instead of a distinct object
         | 
| 17 | 
            +
                def self.create(attrs)
         | 
| 18 | 
            +
                  begin
         | 
| 19 | 
            +
                    merge = new(attrs)
         | 
| 20 | 
            +
             | 
| 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 | 
            +
                    target, source = merge.get_relations
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    Related::Relationship.create :merges, target, source
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    # relate the branches as well
         | 
| 28 | 
            +
                    Related::Relationship.create :related, source.branch, target.branch
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    Related::Relationship.create :included, source.branch, target
         | 
| 31 | 
            +
                    Related::Relationship.create :included, target.branch, source
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    merge
         | 
| 34 | 
            +
                  rescue Related::NotFound => ex
         | 
| 35 | 
            +
                    # 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 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def save
         | 
| 42 | 
            +
                  # nothing, no need to save
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def get_relations
         | 
| 46 | 
            +
                  return get_target, get_source
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def get_source
         | 
| 50 | 
            +
                  Changeset.find(source_version)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def get_target
         | 
| 54 | 
            +
                  Changeset.find(target_version)
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              class Entity < Related::Node
         | 
| 3 | 
            +
                def self.inherited(klass)
         | 
| 4 | 
            +
                  define_singleton_method :act_as_entity do
         | 
| 5 | 
            +
                    klass::SCHEMA.each do |key, details|
         | 
| 6 | 
            +
                      property key, details[:type]
         | 
| 7 | 
            +
                    end
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                private
         | 
| 12 | 
            +
                def schema
         | 
| 13 | 
            +
                  self.class::SCHEMA
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require 'tfs_graph/project/project_store'
         | 
| 2 | 
            +
            require 'tfs_graph/branch/branch_store'
         | 
| 3 | 
            +
            require 'tfs_graph/changeset/changeset_store'
         | 
| 4 | 
            +
            require 'tfs_graph/changeset_merge/changeset_merge_store'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'tfs_graph/associators/changeset_tree_creator'
         | 
| 7 | 
            +
            require 'tfs_graph/associators/branch_associator'
         | 
| 8 | 
            +
            require 'tfs_graph/branch/branch_archive_handler'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            require 'tfs_graph/populators'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            BranchNotFound = Class.new(Exception)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            module TFSGraph
         | 
| 15 | 
            +
              class GraphPopulator
         | 
| 16 | 
            +
                include Populators
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                class << self
         | 
| 19 | 
            +
                  include StoreHelpers
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def populate_graph(type=Everything, *args)
         | 
| 22 | 
            +
                    populator = type.new *args
         | 
| 23 | 
            +
                    populator.populate
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def incrementally_update_all
         | 
| 27 | 
            +
                    populate_graph(Populators::SinceLast)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def populate_all_from_time(time)
         | 
| 31 | 
            +
                    populate_graph(Populators::SinceDate, time)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              class Normalizer
         | 
| 3 | 
            +
                class << self
         | 
| 4 | 
            +
                  def normalize_many(data)
         | 
| 5 | 
            +
                    data.map {|item| normalize item }
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def normalize(item)
         | 
| 9 | 
            +
                    representation = {}
         | 
| 10 | 
            +
                    schema.each do |key, lookup|
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      if lookup[:key].present?  # for keys that pull data from other sources
         | 
| 13 | 
            +
                        value = item.send lookup[:key]
         | 
| 14 | 
            +
                        value = lookup[:converter].call(value) if lookup[:converter].present?
         | 
| 15 | 
            +
                      else
         | 
| 16 | 
            +
                        value = lookup[:default]
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      representation[key] = value
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                    representation
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  private
         | 
| 25 | 
            +
                  def schema
         | 
| 26 | 
            +
                    raise NoMethodError, "please define the schema in the Normalizer subclass"
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              module Populators
         | 
| 3 | 
            +
                class Everything
         | 
| 4 | 
            +
                  include Utilities
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def populate
         | 
| 7 | 
            +
                    clean
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    collect_projects.map do |project|
         | 
| 10 | 
            +
                      branches = collect_branches(project)
         | 
| 11 | 
            +
                      branches.map {|branch| collect_changesets(branch) }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      branches.each {|branch| collect_merges(branch) }
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    finalize
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              module Populators
         | 
| 3 | 
            +
                class ForProject
         | 
| 4 | 
            +
                  include Utilities
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(project)
         | 
| 7 | 
            +
                    @project = project
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def populate
         | 
| 11 | 
            +
                    branches = collect_branches(@project)
         | 
| 12 | 
            +
                    branches.map {|branch| collect_changesets(branch) }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    branches.each {|branch| collect_merges(branch) }
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              module Populators
         | 
| 3 | 
            +
                class SinceDate
         | 
| 4 | 
            +
                  include Utilities
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(since)
         | 
| 7 | 
            +
                    @since = since
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def populate
         | 
| 11 | 
            +
                    clean
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    collect_projects.map do |project|
         | 
| 14 | 
            +
                      branches = collect_branches(project)
         | 
| 15 | 
            +
                      branches.map do |branch|
         | 
| 16 | 
            +
                        collect_changesets(branch, :cache_since_date, @since)
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      branches.each {|branch| collect_merges(branch) }
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    finalize
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              module Populators
         | 
| 3 | 
            +
                class SinceLast
         | 
| 4 | 
            +
                  include Utilities
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def populate
         | 
| 7 | 
            +
                    ProjectStore.all_cached.map do |project|
         | 
| 8 | 
            +
                      new_changesets = project.active_branches.map {|branch| collect_changesets branch, :cache_since_last_update}
         | 
| 9 | 
            +
                      new_branches = BranchStore.new(project).cache_since_last_update
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                      new_changesets.concat new_branches.map {|branch| collect_changesets branch }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      # recache and reassociate all merges for all branches.
         | 
| 14 | 
            +
                      # should not lead to dupes thanks to Related
         | 
| 15 | 
            +
                      new_branches.concat(project.branches).each do |branch|
         | 
| 16 | 
            +
                        collect_merges(branch)
         | 
| 17 | 
            +
                        BranchAssociator.associate(branch.changesets)
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    finalize
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              module Populators
         | 
| 3 | 
            +
                module Utilities
         | 
| 4 | 
            +
                  include StoreHelpers
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def clean
         | 
| 7 | 
            +
                    flush_all
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def finalize
         | 
| 11 | 
            +
                    BranchArchiveHandler.hide_all_archives
         | 
| 12 | 
            +
                    mark_as_updated
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def collect_projects
         | 
| 16 | 
            +
                    ProjectStore.cache
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def collect_branches(project)
         | 
| 20 | 
            +
                    BranchStore.new(project).cache_all
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def collect_changesets(branch, method=:cache_all, *args)
         | 
| 24 | 
            +
                    changesets = ChangesetStore.new(branch).send(method, *args)
         | 
| 25 | 
            +
                    generate_branch_tree(branch)
         | 
| 26 | 
            +
                    changesets.compact
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def generate_branch_tree(branch)
         | 
| 30 | 
            +
                    ChangesetTreeCreator.to_tree branch
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def collect_merges(branch)
         | 
| 34 | 
            +
                    ChangesetMergeStore.new(branch).cache
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            require_relative 'populators/utilities'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative 'populators/everything'
         | 
| 4 | 
            +
            require_relative 'populators/since_last'
         | 
| 5 | 
            +
            require_relative 'populators/since_date'
         | 
| 6 | 
            +
            require_relative 'populators/for_project'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module TFSGraph
         | 
| 9 | 
            +
              module Populators
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require 'tfs_graph/tfs_client'
         | 
| 2 | 
            +
            require 'tfs_graph/project/project_normalizer'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TFSGraph
         | 
| 5 | 
            +
              class ProjectStore
         | 
| 6 | 
            +
                extend TFSClient
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class << self
         | 
| 9 | 
            +
                  def cache
         | 
| 10 | 
            +
                    projects = tfs.projects.run
         | 
| 11 | 
            +
                    normalized = ProjectNormalizer.normalize_many projects
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    normalized.map do |project_attrs|
         | 
| 14 | 
            +
                      project = Project.create project_attrs
         | 
| 15 | 
            +
                      Related::Relationship.create(:projects, Related.root, project)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      project
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def all_cached
         | 
| 22 | 
            +
                    Related.root.outgoing(:projects).options(model: Project).nodes.to_a
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def find_cached(name)
         | 
| 26 | 
            +
                    all_cached.detect {|p| p.name == name }
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,59 @@ | |
| 1 | 
            +
            require 'tfs_graph/entity'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module TFSGraph
         | 
| 4 | 
            +
              class Project < Entity
         | 
| 5 | 
            +
                extend Comparable
         | 
| 6 | 
            +
                SCHEMA = {
         | 
| 7 | 
            +
                  name: {key: "Name"}
         | 
| 8 | 
            +
                }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                act_as_entity
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def <=>(other)
         | 
| 13 | 
            +
                  name <=> other.name
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def last_change
         | 
| 17 | 
            +
                  branches.map {|b| b.last_changeset }
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def all_activity
         | 
| 21 | 
            +
                  branches.map {|b| b.changesets }.flatten
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def all_activity_by_date(limiter=nil)
         | 
| 25 | 
            +
                  raise InvalidArgument("parameter must be a Date") unless limiter.nil? || limiter.is_a?(Time)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  activity = all_activity
         | 
| 28 | 
            +
                  activity = activity.select {|c| c.created > limiter } unless limiter.nil?
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  activity.group_by(&:formatted_created)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def active_branches
         | 
| 34 | 
            +
                  branches.reject(&:archived?)
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def branches
         | 
| 38 | 
            +
                  branches_with_hidden.reject(&:hidden?)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def branches_with_hidden
         | 
| 42 | 
            +
                  outgoing(:branches).options(model: Branch).nodes.to_a
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                %w(master release feature).each do |type|
         | 
| 46 | 
            +
                  define_method "#{type}s" do
         | 
| 47 | 
            +
                    branches.select {|b| b.send "#{type}?" }
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  define_method "#{type}s_with_hidden" do
         | 
| 51 | 
            +
                    branches_with_hidden.select {|b| b.send "#{type}?" }
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  define_method "archived_#{type}s" do
         | 
| 55 | 
            +
                    branches.select {|b| b.send("#{type}?") && b.archived? }
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            require 'time'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module TFSGraph
         | 
| 4 | 
            +
              module StoreHelpers
         | 
| 5 | 
            +
                UPDATED_KEY = "LAST_UPDATED_ON"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # flush by key so that we only disturbe our namespace
         | 
| 8 | 
            +
                def flush_all
         | 
| 9 | 
            +
                  redis.keys("*").each do |k|
         | 
| 10 | 
            +
                    redis.del k
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def mark_as_updated(time=nil)
         | 
| 15 | 
            +
                  time ||= Time.now
         | 
| 16 | 
            +
                  redis.set UPDATED_KEY, time.utc
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def last_updated_on
         | 
| 20 | 
            +
                  date = redis.get(UPDATED_KEY)
         | 
| 21 | 
            +
                  return Time.now unless date
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  Time.parse(date).localtime
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                private
         | 
| 27 | 
            +
                def redis
         | 
| 28 | 
            +
                  Related.redis
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # Wraps TFS OData domain knowledge
         | 
| 2 | 
            +
            require 'tfs'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TFSGraph
         | 
| 5 | 
            +
              module TFSClient
         | 
| 6 | 
            +
                InvalidConfig = Class.new(RuntimeError)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                REQUIRED_KEYS = [:endpoint, :collection, :username, :password]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # Requires a hash of settings
         | 
| 11 | 
            +
                def setup(settings=TFSGraph.config.tfs)
         | 
| 12 | 
            +
                  raise InvalidConfig unless REQUIRED_KEYS.all? {|key| settings.keys.include? key }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  TFS.configure do |c|
         | 
| 15 | 
            +
                    c.endpoint = endpoint(settings)
         | 
| 16 | 
            +
                    c.username = settings[:username]
         | 
| 17 | 
            +
                    c.password = settings[:password]
         | 
| 18 | 
            +
                    c.namespace = settings[:namespace] || "TFS"
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def tfs
         | 
| 23 | 
            +
                  @tfs ||= begin
         | 
| 24 | 
            +
                    setup
         | 
| 25 | 
            +
                    TFS.client
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def tfs=(client)
         | 
| 30 | 
            +
                  @tfs = client
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def endpoint(settings)
         | 
| 34 | 
            +
                  "#{settings[:endpoint]}/#{settings[:collection]}"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            module TFSGraph
         | 
| 2 | 
            +
              module TFSHelpers
         | 
| 3 | 
            +
                def branch_base(path)
         | 
| 4 | 
            +
                  branch_path_to_name(path).split('-').first
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # handles OData paths: $>RJR>Project>Path
         | 
| 8 | 
            +
                def branch_path_to_name(path)
         | 
| 9 | 
            +
                  path_parts(path).last
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # handles TFS server paths: $/RJR/Project/Path
         | 
| 13 | 
            +
                def server_path_to_odata_path(path)
         | 
| 14 | 
            +
                  path.gsub "/", ">"
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def odata_path_to_server_path(path)
         | 
| 18 | 
            +
                  path.gsub ">", "/"
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def branch_project(path)
         | 
| 22 | 
            +
                  path_parts(path)[1]
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def base_username(name)
         | 
| 26 | 
            +
                  name.split(/\/|\\/).last
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def scrub_changeset(version)
         | 
| 30 | 
            +
                  version.gsub /\D/, "" unless version.nil?
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                private
         | 
| 34 | 
            +
                def path_parts(path)
         | 
| 35 | 
            +
                  path.split(">")
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def server_path_parts(path)
         | 
| 39 | 
            +
                  path.split("/")
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
    
        data/lib/tfs_graph.rb
    ADDED
    
    | @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require "related"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "tfs_graph/version"
         | 
| 4 | 
            +
            require "tfs_graph/config"
         | 
| 5 | 
            +
            require 'tfs_graph/graph_populator'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module TFSGraph
         | 
| 8 | 
            +
              class << self
         | 
| 9 | 
            +
                def config
         | 
| 10 | 
            +
                  return @config unless block_given?
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  @config ||= begin
         | 
| 13 | 
            +
                    config = Config.new
         | 
| 14 | 
            +
                    yield config
         | 
| 15 | 
            +
                    config
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
    
        data/spec/factories.rb
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require 'tfs_graph/changeset'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            FactoryGirl.define do
         | 
| 4 | 
            +
              factory :changeset, class: TFSGraph::Changeset do
         | 
| 5 | 
            +
                comment "Doing fun things"
         | 
| 6 | 
            +
                committer "John Doe"
         | 
| 7 | 
            +
                created { Time.now }
         | 
| 8 | 
            +
                sequence :id
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              factory :branch do
         | 
| 12 | 
            +
                original_path "$>DefaultCollection>Project"
         | 
| 13 | 
            +
                path "$>DefaultCollection>Project"
         | 
| 14 | 
            +
                project "BFG"
         | 
| 15 | 
            +
                name "Project"
         | 
| 16 | 
            +
                root "$>DefaultCollection>Project"
         | 
| 17 | 
            +
                created { Time.now }
         | 
| 18 | 
            +
                type "master"
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'tfs_graph/tfs_helpers'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class DemoClass; include TFSGraph::TFSHelpers; end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            describe TFSGraph::TFSHelpers do
         | 
| 7 | 
            +
              Given(:demo) { DemoClass.new }
         | 
| 8 | 
            +
              Given(:archived_path) { "$>RJR>_Branches>FAQ>RJRLibraries-FAQ" }
         | 
| 9 | 
            +
              Given(:normal_path) { "$>RJR>Grizzly" }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              context "can parse name of branch" do
         | 
| 12 | 
            +
                When(:archived_result) { demo.branch_path_to_name(archived_path) }
         | 
| 13 | 
            +
                Then { archived_result.should eq("RJRLibraries-FAQ") }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                When(:normal_result) { demo.branch_path_to_name(normal_path) }
         | 
| 16 | 
            +
                Then { normal_result.should eq("Grizzly") }
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              context "can parse down base name from a path" do
         | 
| 20 | 
            +
                When(:archived_result) { demo.branch_base(archived_path) }
         | 
| 21 | 
            +
                Then { archived_result.should eq("RJRLibraries") }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                When(:normal_result) { demo.branch_base(normal_path) }
         | 
| 24 | 
            +
                Then { normal_result.should eq("Grizzly") }
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              context "can parse base username from tfs" do
         | 
| 28 | 
            +
                When(:fwd) { demo.base_username("BFGCOM/tmoe") }
         | 
| 29 | 
            +
                Then { fwd.should eq("tmoe") }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                When(:bck) { demo.base_username("BFGCOM\\tmoe") }
         | 
| 32 | 
            +
                Then { bck.should eq("tmoe") }
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              context "can scrub out letters from changeset version" do
         | 
| 36 | 
            +
                When(:version_1) { demo.scrub_changeset("C1234") }
         | 
| 37 | 
            +
                Then { version_1.should eq("1234") }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                When(:version_2) { demo.scrub_changeset("1234") }
         | 
| 40 | 
            +
                Then { version_2.should eq("1234") }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                context "does nothing if no changeset given" do
         | 
| 43 | 
            +
                  When(:version) { demo.scrub_changeset(nil) }
         | 
| 44 | 
            +
                  Then { version.should_not have_failed }
         | 
| 45 | 
            +
                  And { version.should == nil }
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            $LOAD_PATH.unshift "../lib"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'related'
         | 
| 4 | 
            +
            require 'rspec/given'
         | 
| 5 | 
            +
            require 'vcr'
         | 
| 6 | 
            +
            require 'factory_girl'
         | 
| 7 | 
            +
            require 'pry'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            FactoryGirl.definition_file_paths = %w{./factories ./spec/factories}
         | 
| 10 | 
            +
            FactoryGirl.find_definitions
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            require 'tfs_graph'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            VCR.configure do |c|
         | 
| 15 | 
            +
              c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
         | 
| 16 | 
            +
              c.hook_into :webmock
         | 
| 17 | 
            +
              c.allow_http_connections_when_no_cassette = true
         | 
| 18 | 
            +
              c.default_cassette_options = { record: :new_episodes }
         | 
| 19 | 
            +
              c.configure_rspec_metadata!
         | 
| 20 | 
            +
            end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            RSpec.configure do |config|
         | 
| 23 | 
            +
              config.mock_with :rspec
         | 
| 24 | 
            +
              config.include FactoryGirl::Syntax::Methods
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              config.before(:each) do
         | 
| 27 | 
            +
                TFSGraph.config do |c|
         | 
| 28 | 
            +
                  c.tfs = {
         | 
| 29 | 
            +
                    username: 'BFGCOM\apiservice',
         | 
| 30 | 
            +
                    password: "BFGservice123",
         | 
| 31 | 
            +
                    endpoint: "https://tfs-dev-01.bfgdev.inside/RAI"
         | 
| 32 | 
            +
                  }
         | 
| 33 | 
            +
                  c.redis = "localhost:6379/test"
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              config.after(:each) do
         | 
| 38 | 
            +
                r = Related.redis
         | 
| 39 | 
            +
                r.keys.each do |key|
         | 
| 40 | 
            +
                  r.del key
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
    
        data/tfs_graph.gemspec
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'tfs_graph/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "tfs_graph"
         | 
| 8 | 
            +
              spec.version       = TFSGraph::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Luke van der Hoeven"]
         | 
| 10 | 
            +
              spec.email         = ["hungerandthirst@gmail.com"]
         | 
| 11 | 
            +
              spec.description   = %q{A library to help cache and fetch TFS data}
         | 
| 12 | 
            +
              spec.summary       = %q{Simple graph db wrapper for TFS data for Redis caching}
         | 
| 13 | 
            +
              spec.homepage      = ""
         | 
| 14 | 
            +
              spec.license       = "MIT"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              spec.files         = `git ls-files`.split($/)
         | 
| 17 | 
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 18 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 19 | 
            +
              spec.require_paths = ["lib"]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              spec.add_dependency "ruby_tfs"
         | 
| 22 | 
            +
              spec.add_dependency "related"
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              spec.add_development_dependency "bundler", "~> 1.3"
         | 
| 25 | 
            +
              spec.add_development_dependency "rake"
         | 
| 26 | 
            +
            end
         |