metior 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.travis.yml +2 -0
  2. data/.yardopts +1 -0
  3. data/Changelog.md +23 -0
  4. data/Gemfile +1 -17
  5. data/Gemfile.lock +28 -21
  6. data/README.md +66 -20
  7. data/lib/metior.rb +30 -14
  8. data/lib/metior/actor.rb +28 -22
  9. data/lib/metior/auto_include_vcs.rb +43 -0
  10. data/lib/metior/collections/actor_collection.rb +97 -0
  11. data/lib/metior/collections/collection.rb +84 -0
  12. data/lib/metior/collections/commit_collection.rb +309 -0
  13. data/lib/metior/commit.rb +128 -48
  14. data/lib/metior/errors.rb +2 -2
  15. data/lib/metior/git/commit.rb +32 -31
  16. data/lib/metior/git/repository.rb +71 -6
  17. data/lib/metior/github/commit.rb +5 -16
  18. data/lib/metior/github/repository.rb +68 -40
  19. data/lib/metior/report.rb +139 -0
  20. data/lib/metior/report/view.rb +120 -0
  21. data/lib/metior/report/view_helper.rb +47 -0
  22. data/lib/metior/repository.rb +225 -56
  23. data/lib/metior/vcs.rb +12 -3
  24. data/lib/metior/version.rb +1 -1
  25. data/metior.gemspec +28 -26
  26. data/reports/default.rb +17 -0
  27. data/reports/default/images/favicon.png +0 -0
  28. data/reports/default/stylesheets/default.css +128 -0
  29. data/reports/default/templates/actor/minimal.mustache +1 -0
  30. data/reports/default/templates/commit/minimal.mustache +1 -0
  31. data/reports/default/templates/index.mustache +27 -0
  32. data/reports/default/templates/most_significant_authors.mustache +11 -0
  33. data/reports/default/templates/most_significant_commits.mustache +13 -0
  34. data/reports/default/templates/repository_information.mustache +17 -0
  35. data/reports/default/templates/top_committers.mustache +11 -0
  36. data/reports/default/views/index.rb +33 -0
  37. data/reports/default/views/most_significant_authors.rb +19 -0
  38. data/reports/default/views/most_significant_commits.rb +19 -0
  39. data/reports/default/views/repository_information.rb +47 -0
  40. data/reports/default/views/top_committers.rb +21 -0
  41. data/test/fixtures.rb +54 -36
  42. data/test/helper.rb +10 -3
  43. data/test/{test_class_loading.rb → test_1st_class_loading.rb} +1 -1
  44. data/test/test_actor_colletion.rb +78 -0
  45. data/test/test_collection.rb +61 -0
  46. data/test/test_commit_collection.rb +139 -0
  47. data/test/test_git.rb +58 -5
  48. data/test/test_github.rb +52 -9
  49. data/test/test_metior.rb +22 -1
  50. data/test/test_report.rb +49 -0
  51. data/test/test_repository.rb +46 -9
  52. data/test/test_vcs.rb +36 -13
  53. metadata +105 -43
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # Copyright (c) 2011, Sebastian Staudt
5
5
 
6
- require 'rash'
6
+ require 'hashie/mash'
7
7
  require 'time'
8
8
 
9
9
  module Fixtures
@@ -18,14 +18,21 @@ module Fixtures
18
18
  commits = []
19
19
 
20
20
  commit = {}
21
+ last_commit = nil
21
22
  file.lines.each do |line|
22
23
  line.strip!
23
24
 
24
25
  next if line.empty?
25
26
 
26
- if line.match /^[AMD]\0/
27
- commit[:files] = [] unless commit.key? :files
28
- commit[:files] << line.split("\0")
27
+ if line.match /^[A]\0/
28
+ commit[:added_files] = [] unless commit.key? :added_files
29
+ commit[:added_files] << line.split("\0").last.strip
30
+ elsif line.match /^[D]\0/
31
+ commit[:modified_files] = [] unless commit.key? :modified_files
32
+ commit[:modified_files] << line.split("\0").last.strip
33
+ elsif line.match /^[M]\0/
34
+ commit[:deleted_files] = [] unless commit.key? :deleted_files
35
+ commit[:deleted_files] << line.split("\0").last.strip
29
36
  elsif line.match /\d+\0\d+$/
30
37
  commit[:impact] = line.split("\0")
31
38
  else
@@ -45,7 +52,9 @@ module Fixtures
45
52
  end
46
53
 
47
54
  if commit != {}
55
+ last_commit[:parent] = commit unless last_commit.nil?
48
56
  commits << commit
57
+ last_commit = commit
49
58
  commit = {}
50
59
  end
51
60
  end
@@ -58,42 +67,48 @@ module Fixtures
58
67
  end
59
68
 
60
69
  def self.commits_as_grit_commits(range)
61
- commits = commits(range)
62
-
63
- commits.map do |commit|
64
- grit_commit = Grit::Commit.new(
65
- nil,
66
- commit[:ids].first,
67
- [],
68
- nil,
69
- Grit::Actor.new(commit[:info][4], commit[:info][5]),
70
- Time.at(commit[:info][6].to_i),
71
- Grit::Actor.new(commit[:info][1], commit[:info][2]),
72
- Time.at(commit[:info][3].to_i),
73
- commit[:info].first.lines.to_a
74
- )
75
-
76
- grit_commit.stubs(:diffs).returns []
77
-
78
- stats = Hashie::Rash.new
79
- if commit.key? :impact
80
- stats.additions = commit[:impact].first.to_i
81
- stats.deletions = commit[:impact].last.to_i
82
- else
83
- stats.additions = 0
84
- stats.deletions = 0
85
- end
86
- grit_commit.stubs(:stats).returns stats
87
-
88
- grit_commit
70
+ commits = commits(range).map do |commit|
71
+ parents = commit[:parent].nil? ? [] : [commit[:parent]]
72
+
73
+ diffs = []
74
+ commit[:added_files].each do |added_file|
75
+ diffs << { :new_file => true, :b_path => added_file }
76
+ end if commit.key? :added_files
77
+ commit[:deleted_files].each do |deleted_file|
78
+ diffs << { :deleted_file => true, :b_path => deleted_file }
79
+ end if commit.key? :deleted_files
80
+ commit[:modified_files].each do |modified_file|
81
+ diffs << { :b_path => modified_file }
82
+ end if commit.key? :modified_files
83
+
84
+ Hashie::Mash.new({
85
+ :author => {
86
+ :email => commit[:info][5],
87
+ :name => commit[:info][4]
88
+ },
89
+ :authored_data => Time.at(commit[:info][6].to_i),
90
+ :committer => {
91
+ :email => commit[:info][2],
92
+ :name => commit[:info][1]
93
+ },
94
+ :committed_date => Time.at(commit[:info][3].to_i),
95
+ :diffs => diffs,
96
+ :id => commit[:ids].first,
97
+ :message => commit[:info].first,
98
+ :parents => parents.map { |p| { :id => p[:ids].first } },
99
+ :stats => {
100
+ :additions => commit.key?(:impact) ? commit[:impact].first.to_i : 0,
101
+ :deletions => commit.key?(:impact) ? commit[:impact].last.to_i : 0
102
+ }
103
+ })
89
104
  end
105
+
106
+ HASH_CLASS[commits.map { |c| [c.id, c] }]
90
107
  end
91
108
 
92
109
  def self.commits_as_rashies(range)
93
- commits = commits(range)
94
-
95
- commits.map do |commit|
96
- Hashie::Rash.new({
110
+ commits = commits(range).map do |commit|
111
+ Hashie::Mash.new({
97
112
  :author => {
98
113
  :email => commit[:info][4],
99
114
  :login => commit[:info][5],
@@ -108,8 +123,11 @@ module Fixtures
108
123
  },
109
124
  :id => commit[:ids].first,
110
125
  :message => commit[:info].first,
126
+ :parents => ([{ :id => commit[:parent][:ids].first }] rescue [])
111
127
  })
112
128
  end
129
+
130
+ HASH_CLASS[commits.map { |c| [c.id, c] }]
113
131
  end
114
132
 
115
133
  end
@@ -3,14 +3,21 @@
3
3
  #
4
4
  # Copyright (c) 2011, Sebastian Staudt
5
5
 
6
+ require 'test/unit'
7
+
8
+ require 'rubygems'
9
+ require 'bundler'
10
+
11
+ Bundler.setup
12
+
13
+ require 'mocha'
14
+ require 'shoulda'
15
+
6
16
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
7
17
  $LOAD_PATH.unshift File.dirname(__FILE__)
8
18
  require 'metior'
9
19
  include Metior
10
20
 
11
- Bundler.setup
12
- Bundler.require :test
13
-
14
21
  # Extends TestCase functionality
15
22
  class Test::Unit::TestCase
16
23
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  require 'helper'
7
7
 
8
- class TestClassLoading < Test::Unit::TestCase
8
+ class Test1stClassLoading < Test::Unit::TestCase
9
9
 
10
10
  context 'Metior' do
11
11
 
@@ -0,0 +1,78 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2011, Sebastian Staudt
5
+
6
+ require 'fixtures'
7
+ require 'helper'
8
+ require 'metior/collections/actor_collection'
9
+
10
+ class TestActorCollection < Test::Unit::TestCase
11
+
12
+ context 'A collection of actors' do
13
+
14
+ setup do
15
+ repo = Metior::Git::Repository.new File.dirname(File.dirname(__FILE__))
16
+ @@grit_commits ||= Fixtures.commits_as_grit_commits(''..'master')
17
+ Grit::Repo.any_instance.stubs(:commits).returns @@grit_commits.values
18
+ @@grit_commits.each do |id, commit|
19
+ Grit::Repo.any_instance.stubs(:commit).with(id).returns commit
20
+ end
21
+ @authors = repo.authors
22
+ end
23
+
24
+ should 'be an instance of Collection' do
25
+ assert_kind_of Collection, @authors
26
+ end
27
+
28
+ should 'allow to get all the commits authored by those actors' do
29
+ commits = @authors.authored_commits
30
+ assert_instance_of CommitCollection, commits
31
+ assert_equal 460, commits.size
32
+ assert_equal '1b2fe77', commits.first.id
33
+ assert_equal '80f136f', commits.last.id
34
+ end
35
+
36
+ should 'allow to get the commits authored by a single of those actors' do
37
+ commits = @authors.authored_commits 'tom@mojombo.com'
38
+ assert_instance_of CommitCollection, commits
39
+ assert_equal 173, commits.size
40
+ assert_equal 'a3c5139', commits.first.id
41
+ assert_equal '634396b', commits.last.id
42
+ end
43
+
44
+ should 'allow to get all the commits committed by those actors' do
45
+ commits = @authors.committed_commits
46
+ assert_instance_of CommitCollection, commits
47
+ assert_equal 460, commits.size
48
+ assert_equal '1b2fe77', commits.first.id
49
+ assert_equal '80f136f', commits.last.id
50
+ end
51
+
52
+ should 'allow to get the commits committed by a single of those actors' do
53
+ commits = @authors.committed_commits 'technoweenie@gmail.com'
54
+ assert_instance_of CommitCollection, commits
55
+ assert_equal 55, commits.size
56
+ assert_equal 'ed1b3ae', commits.first.id
57
+ assert_equal 'c9cf68f', commits.last.id
58
+ end
59
+
60
+ should 'allow to get the most significant actors' do
61
+ authors = @authors.most_significant
62
+ assert_instance_of ActorCollection, authors
63
+ assert_equal 3, authors.size
64
+ assert_equal 'tom@mojombo.com', authors.first.id
65
+ assert_equal 'rsanheim@gmail.com', authors.last.id
66
+ end
67
+
68
+ should 'allow to get the top contributing actors' do
69
+ authors = @authors.top
70
+ assert_instance_of ActorCollection, authors
71
+ assert_equal 3, authors.size
72
+ assert_equal 'tom@mojombo.com', authors.first.id
73
+ assert_equal 'technoweenie@gmail.com', authors.last.id
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,61 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2011, Sebastian Staudt
5
+
6
+ require 'helper'
7
+ require 'metior/collections/collection'
8
+
9
+ class Dummy
10
+ def id
11
+ __id__
12
+ end
13
+ end
14
+
15
+ class TestCollections < Test::Unit::TestCase
16
+
17
+ context 'A collection of objects' do
18
+
19
+ setup do
20
+ @collection = Collection.new
21
+ @object1 = Dummy.new
22
+ @object2 = Dummy.new
23
+ @object3 = Dummy.new
24
+ @collection << @object1
25
+ @collection << @object2
26
+ @collection << @object3
27
+ end
28
+
29
+ should 'have a simple constructor' do
30
+ collection = Collection.new [@object1, @object2, @object3]
31
+ assert_equal [@object1.id, @object2.id, @object3.id], collection.keys
32
+ assert_equal @object1, collection[@object1.id]
33
+ assert_equal @object2, collection[@object2.id]
34
+ assert_equal @object3, collection[@object3.id]
35
+ end
36
+
37
+ should 'be a subclass of Hash' do
38
+ assert_kind_of Hash, @collection
39
+ assert_kind_of OrderedHash, @collection if RUBY_VERSION.match(/^1\.8/)
40
+ end
41
+
42
+ should 'have a working << operator' do
43
+ object = Dummy.new
44
+ @collection << object
45
+ assert_equal object, @collection[object.id]
46
+ end
47
+
48
+ should 'have a working #each method' do
49
+ objects = []
50
+ result = @collection.each { |obj| objects << obj }
51
+ assert_equal @collection, result
52
+ assert_equal [@object1, @object2, @object3], objects
53
+ end
54
+
55
+ should 'have a working #last method' do
56
+ assert_equal @object3, @collection.last
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,139 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2011, Sebastian Staudt
5
+
6
+ require 'fixtures'
7
+ require 'helper'
8
+ require 'metior/collections/commit_collection'
9
+
10
+ class TestCommitCollection < Test::Unit::TestCase
11
+
12
+ context 'A collection of commits' do
13
+
14
+ setup do
15
+ repo = Metior::Git::Repository.new File.dirname(File.dirname(__FILE__))
16
+ @@grit_commits ||= Fixtures.commits_as_grit_commits(''..'master')
17
+ Grit::Repo.any_instance.stubs(:commits).returns @@grit_commits.values
18
+ @@grit_commits.each do |id, commit|
19
+ Grit::Repo.any_instance.stubs(:commit).with(id).returns commit
20
+ end
21
+ @commits = repo.commits
22
+ end
23
+
24
+ should 'be an instance of Collection' do
25
+ assert_kind_of Collection, @commits
26
+ end
27
+
28
+ should 'allow to get all the authors of those commits' do
29
+ authors = @commits.authors
30
+ assert_instance_of ActorCollection, authors
31
+ assert_equal 37, authors.size
32
+ assert_equal 'rtomayko@gmail.com', authors.first.id
33
+ assert_equal 'tom@taco.(none)', authors.last.id
34
+ end
35
+
36
+ should 'allow to get the author of a single of those commits' do
37
+ authors = @commits.authors '4c592b4'
38
+ assert_instance_of ActorCollection, authors
39
+ assert_equal 1, authors.size
40
+ assert_equal 'bobbywilson0@gmail.com', authors.first.id
41
+ end
42
+
43
+ should 'allow to get all commits of a specific author' do
44
+ commits = @commits.by 'rtomayko@gmail.com'
45
+ assert_instance_of CommitCollection, commits
46
+ assert_equal 47, commits.size
47
+ assert_equal '1b2fe77', commits.first.id
48
+ assert_equal 'd731f85', commits.last.id
49
+ end
50
+
51
+ should 'allow to get all commits of a some authors' do
52
+ commits = @commits.by 'tom@mojombo.com', 'rtomayko@gmail.com'
53
+ assert_instance_of CommitCollection, commits
54
+ assert_equal 220, commits.size
55
+ assert_equal '1b2fe77', commits.first.id
56
+ assert_equal '634396b', commits.last.id
57
+ end
58
+
59
+ should 'allow to get all commits after a given date' do
60
+ commits = @commits.after '31-12-2010'
61
+ assert_instance_of CommitCollection, commits
62
+ assert_equal 29, commits.size
63
+ assert_equal '1b2fe77', commits.first.id
64
+ assert_equal '696761d', commits.last.id
65
+ end
66
+
67
+ should 'allow to get all commits before a given date' do
68
+ commits = @commits.before '31-12-2009'
69
+ assert_instance_of CommitCollection, commits
70
+ assert_equal 325, commits.size
71
+ assert_equal '2f1f63e', commits.first.id
72
+ assert_equal '634396b', commits.last.id
73
+ end
74
+
75
+ should 'allow to get all the committers of those commits' do
76
+ committers = @commits.committers
77
+ assert_instance_of ActorCollection, committers
78
+ assert_equal 29, committers.size
79
+ assert_equal 'rtomayko@gmail.com', committers.first.id
80
+ assert_equal 'tom@taco.(none)', committers.last.id
81
+ end
82
+
83
+ should 'allow to get the committers of a single of those commits' do
84
+ committers = @commits.committers '4c592b4'
85
+ assert_instance_of ActorCollection, committers
86
+ assert_equal 1, committers.size
87
+ assert_equal 'bobbywilson0@gmail.com', committers.first.id
88
+ end
89
+
90
+ should 'allow to get the activity statistics of those commits' do
91
+ activity = @commits.activity
92
+ assert_instance_of Hash, activity
93
+ assert_instance_of Hash, activity[:active_days]
94
+ assert_equal 157, activity[:active_days].size
95
+ assert activity[:active_days].keys.all? { |k| k.is_a? Time }
96
+ assert activity[:active_days].values.all? { |v| v.is_a? Fixnum }
97
+ assert_in_delta 2.9299, activity[:commits_per_active_day], 0.0001
98
+ assert_equal Time.at(1191997100), activity[:first_commit_date]
99
+ assert_equal Time.at(1306794294), activity[:last_commit_date]
100
+ assert_equal Time.parse('14-02-2009 00:00 +0000'), activity[:most_active_day]
101
+ end
102
+
103
+ should 'allow to get all commits changing specified files' do
104
+ commits = @commits.changing('lib/grit.rb')
105
+ assert_instance_of CommitCollection, commits
106
+ assert_equal 57, commits.size
107
+ assert_equal '18bfda9', commits.first.id
108
+ assert_equal '634396b', commits.last.id
109
+ end
110
+
111
+ should 'allow to get all commits with a minimum impact' do
112
+ commits = @commits.with_impact(100)
113
+ assert_instance_of CommitCollection, commits
114
+ assert_equal 55, commits.size
115
+ assert_equal 'ef2870b', commits.first.id
116
+ assert_equal 'a47fd41', commits.last.id
117
+ end
118
+
119
+ should 'allow to get the most significant commits' do
120
+ commits = @commits.most_significant(5)
121
+ assert_instance_of CommitCollection, commits
122
+ assert_equal 5, commits.size
123
+ assert_equal 'f91f3c8', commits.first.id
124
+ assert_equal '3c230a3', commits.last.id
125
+ end
126
+
127
+ should 'allow to get the line stats of the commits' do
128
+ assert_equal 25546, @commits.additions
129
+ assert_equal 6359, @commits.deletions
130
+ end
131
+
132
+ should 'lazy load the line stats of the commits' do
133
+ @commits.expects(:load_line_stats).once
134
+ @commits.additions
135
+ end
136
+
137
+ end
138
+
139
+ end