churn 0.0.29 → 0.0.30
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/Gemfile.lock +1 -1
- data/README.md +13 -18
- data/bin/churn +7 -1
- data/lib/churn/churn_calculator.rb +19 -12
- data/lib/churn/churn_history.rb +10 -6
- data/lib/churn/version.rb +1 -1
- data/lib/churn_options.rb +31 -0
- data/lib/tasks/churn_tasks.rb +1 -0
- data/test/unit/churn_history_test.rb +3 -3
- data/test/unit/churn_options_test.rb +16 -0
- metadata +6 -3
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
Churn
|
2
|
+
===
|
2
3
|
|
3
4
|
A Project to give the churn file, class, and method for a project for a given checkin. Over time the tool adds up the history of churns to give the number of times a file, class, or method is changing during the life of a project.
|
4
5
|
Churn for files is immediate, but classes and methods requires buildings up a history using churn between revisions. The history is stored in ./tmp
|
@@ -13,13 +14,14 @@ Authors:
|
|
13
14
|
* absurdhero
|
14
15
|
* bf4
|
15
16
|
|
16
|
-
|
17
|
+
## CI Build Status
|
17
18
|
|
18
19
|
[![Build Status](https://secure.travis-ci.org/danmayer/churn.png)](http://travis-ci.org/danmayer/churn)
|
19
20
|
|
20
21
|
This project runs [travis-ci.org](http://travis-ci.org)
|
21
22
|
|
22
|
-
|
23
|
+
## Churn Usage
|
24
|
+
|
23
25
|
Install with `gem install churn` or for bundler add to your Gemfile `gem 'churn', :require => false`.
|
24
26
|
|
25
27
|
The reason you want require false is that when required by default churn is expecting to add some rake tasks, you don't really want or need it loading when running your server or tests. Previous versions required this change, churn will now do the right thing if you forget to add `require => false`.
|
@@ -45,7 +47,7 @@ The reason you want require false is that when required by default churn is expe
|
|
45
47
|
churn --start_date "6 months ago" #Start looking at file changes from 6 months ago
|
46
48
|
|
47
49
|
|
48
|
-
|
50
|
+
## Example Output
|
49
51
|
|
50
52
|
**********************************************************************
|
51
53
|
* Revision Changes
|
@@ -113,7 +115,7 @@ __Example Output__
|
|
113
115
|
| lib/churn/churn_calculator.rb | ChurnCalculator | ChurnCalculator#to_s | 1 |
|
114
116
|
+-------------------------------+-----------------+-----------------------------------------+---------------+
|
115
117
|
|
116
|
-
|
118
|
+
## Options
|
117
119
|
|
118
120
|
[~/projects/churn] churn -h
|
119
121
|
NAME
|
@@ -129,20 +131,13 @@ __Options__
|
|
129
131
|
--start_date=[start_date], -s (0 ~> string(start_date=))
|
130
132
|
--help, -h
|
131
133
|
|
132
|
-
|
134
|
+
## TODO
|
135
|
+
|
136
|
+
The list of items has been moved to the [churn wafflie.io](http://waffle.io/danmayer/churn)
|
133
137
|
|
134
|
-
|
135
|
-
* add support for cvs, and darcs
|
136
|
-
* make storage directory configurable instead of using tmp
|
137
|
-
* allow passing in directories to churn
|
138
|
-
* add a filter that allows for other files besides. *.rb to get method/class checks
|
139
|
-
* improve line number matching for Ruby files
|
140
|
-
* add line number matching for other langauges
|
141
|
-
* finish adding better documenation using YARD
|
142
|
-
* rake task for building manpage (currently manually run `ronn -b1 README.rdoc`)
|
143
|
-
* don't output methods and classes on a commit that has none detected (css and view only commits, etc)
|
138
|
+
[![Stories in Ready](https://badge.waffle.io/danmayer/churn.png)](http://waffle.io/danmayer/churn)
|
144
139
|
|
145
|
-
|
140
|
+
## Notes on Patches/Pull Requests
|
146
141
|
|
147
142
|
* Fork the project.
|
148
143
|
* Make your feature addition or bug fix.
|
@@ -153,6 +148,6 @@ __Notes on Patches/Pull Requests__
|
|
153
148
|
bump version in a commit by itself I can ignore when I pull)
|
154
149
|
* Send me a pull request. Bonus points for topic branches.
|
155
150
|
|
156
|
-
|
151
|
+
## Copyright
|
157
152
|
|
158
153
|
Copyright (c) 2013 Dan Mayer. See LICENSE for details.
|
data/bin/churn
CHANGED
@@ -27,9 +27,15 @@ Main do
|
|
27
27
|
default ''
|
28
28
|
end
|
29
29
|
|
30
|
+
option('data_directory', 'd') do
|
31
|
+
cast :string
|
32
|
+
argument :optional
|
33
|
+
default ''
|
34
|
+
end
|
35
|
+
|
30
36
|
def report_churn(output_string)
|
31
37
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'churn', 'churn_calculator')
|
32
|
-
result = Churn::ChurnCalculator.new({:minimum_churn_count => params['minimum_churn_count'].value, :ignore_files => params['ignore_files'].value, :start_date => params['start_date'].value}).report(output_string)
|
38
|
+
result = Churn::ChurnCalculator.new({:minimum_churn_count => params['minimum_churn_count'].value, :ignore_files => params['ignore_files'].value, :start_date => params['start_date'].value, :data_directory => params['data_directory'].value}).report(output_string)
|
33
39
|
unless output_string
|
34
40
|
result = YAML::dump(result)
|
35
41
|
end
|
@@ -13,22 +13,26 @@ require 'hg_analyzer'
|
|
13
13
|
require 'bzr_analyzer'
|
14
14
|
require 'location_mapping'
|
15
15
|
require 'churn_history'
|
16
|
+
require 'churn_options'
|
16
17
|
|
17
18
|
module Churn
|
18
19
|
|
19
|
-
# The work horse of the the churn library.
|
20
|
-
#
|
21
|
-
#
|
20
|
+
# The work horse of the the churn library.
|
21
|
+
# This class takes user input, determins the SCM the user is using.
|
22
|
+
# It then determines changes made during this revision.
|
23
|
+
# Finally it reads all the changes from previous revisions and displays human readable output on the command line.
|
24
|
+
# It can also ouput a yaml format readable by other tools such as metric_fu and Caliper.
|
22
25
|
class ChurnCalculator
|
23
26
|
|
24
27
|
# intialized the churn calculator object
|
25
28
|
def initialize(options={})
|
26
|
-
|
27
|
-
|
28
|
-
@minimum_churn_count =
|
29
|
-
@ignore_files
|
30
|
-
@
|
31
|
-
@source_control
|
29
|
+
@churn_options = ChurnOptions.instance.set_options(options)
|
30
|
+
|
31
|
+
@minimum_churn_count = @churn_options.minimum_churn_count
|
32
|
+
@ignore_files = @churn_options.ignore_files
|
33
|
+
start_date = @churn_options.start_date
|
34
|
+
@source_control = set_source_control(start_date)
|
35
|
+
|
32
36
|
@changes = {}
|
33
37
|
@revision_changes = {}
|
34
38
|
@class_changes = {}
|
@@ -83,9 +87,7 @@ module Churn
|
|
83
87
|
hash
|
84
88
|
end
|
85
89
|
|
86
|
-
|
87
|
-
def to_s
|
88
|
-
hash = to_h[:churn]
|
90
|
+
def self.to_s(hash)
|
89
91
|
result = seperator
|
90
92
|
result +="* Revision Changes \n"
|
91
93
|
result += seperator
|
@@ -108,6 +110,11 @@ module Churn
|
|
108
110
|
result += display_array(method_churn)
|
109
111
|
end
|
110
112
|
|
113
|
+
# Pretty print the data as a string for the user
|
114
|
+
def to_s
|
115
|
+
ChurnCalculator(to_h[:churn])
|
116
|
+
end
|
117
|
+
|
111
118
|
private
|
112
119
|
|
113
120
|
def collect_items(collection, match)
|
data/lib/churn/churn_history.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
module Churn
|
2
2
|
|
3
|
-
#
|
3
|
+
# responsible for storing the churn history to json,
|
4
4
|
# and for loading old churn history data from json.
|
5
5
|
class ChurnHistory
|
6
|
-
|
6
|
+
|
7
7
|
#takes current revision and it's hash_data and stores it
|
8
8
|
def self.store_revision_history(revision, hash_data)
|
9
|
-
FileUtils.
|
10
|
-
File.open("
|
9
|
+
FileUtils.mkdir_p tmp_churn_directory unless File.directory?(tmp_churn_directory)
|
10
|
+
File.open("#{tmp_churn_directory}/#{revision}.json", 'w') {|file| file.write(hash_data.to_json) }
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
#given a previous project revision find and load the churn data from a json file
|
14
14
|
def self.load_revision_data(revision)
|
15
15
|
#load revision data from scratch folder if it exists
|
16
|
-
filename = "
|
16
|
+
filename = "#{tmp_churn_directory}/#{revision}.json"
|
17
17
|
if File.exists?(filename)
|
18
18
|
begin
|
19
19
|
json_data = File.read(filename)
|
@@ -28,6 +28,10 @@ module Churn
|
|
28
28
|
[changed_files, changed_classes, changed_methods]
|
29
29
|
end
|
30
30
|
|
31
|
+
def self.tmp_churn_directory
|
32
|
+
ChurnOptions.instance.data_directory
|
33
|
+
end
|
34
|
+
|
31
35
|
end
|
32
36
|
|
33
37
|
end
|
data/lib/churn/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Churn
|
4
|
+
|
5
|
+
# responsible for storing the churn configuration
|
6
|
+
class ChurnOptions
|
7
|
+
include Singleton
|
8
|
+
DEFAULT_CHURN_DIRECTORY = "tmp/churn"
|
9
|
+
DEFAULT_MINIMUM_CHURN_COUNT = 5
|
10
|
+
|
11
|
+
attr_accessor :data_directory, :minimum_churn_count, :ignore_files, :start_date
|
12
|
+
|
13
|
+
def initialize()
|
14
|
+
@data_directory = DEFAULT_CHURN_DIRECTORY
|
15
|
+
@minimum_churn_count = DEFAULT_MINIMUM_CHURN_COUNT
|
16
|
+
@ignore_files = ['/dev/null']
|
17
|
+
@start_date = '3 months ago'
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_options(options = {})
|
21
|
+
@data_directory = options.fetch(:data_directory){ @data_directory } unless options[:data_directory]==''
|
22
|
+
@minimum_churn_count = options.fetch(:minimum_churn_count){ @minimum_churn_count }.to_i
|
23
|
+
@ignore_files = (options.fetch(:ignore_files){ @ignore_files }).to_s.split(',').map(&:strip)
|
24
|
+
@ignore_files << '/dev/null' unless @ignore_files.include?('/dev/null')
|
25
|
+
@start_date = options[:start_date] if options[:start_date].nil? || options[:start_date]!=''
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/tasks/churn_tasks.rb
CHANGED
@@ -5,6 +5,7 @@ if defined?(RakeFileUtils) # self.respond_to?(:desc)
|
|
5
5
|
{ :minimum_churn_count => ENV['CHURN_MINIMUM_CHURN_COUNT'],
|
6
6
|
:start_date => ENV['CHURN_START_DATE'],
|
7
7
|
:ignore_files => ENV['CHURN_IGNORE_FILES'],
|
8
|
+
:data_directory => ENV['CHURN_DATA_DIRECTORY'],
|
8
9
|
}.each {|k,v| params[k] = v unless v.nil? }
|
9
10
|
Churn::ChurnCalculator.new(params).report
|
10
11
|
end
|
@@ -5,15 +5,15 @@ class ChurnHistoryTest < Test::Unit::TestCase
|
|
5
5
|
should "store results" do
|
6
6
|
within_construct do |container|
|
7
7
|
Churn::ChurnHistory.store_revision_history('aaa','data')
|
8
|
-
assert File.exists?('tmp/aaa.json')
|
9
|
-
data = File.read('tmp/aaa.json')
|
8
|
+
assert File.exists?('tmp/churn/aaa.json')
|
9
|
+
data = File.read('tmp/churn/aaa.json')
|
10
10
|
assert data.match(/data/)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
should "restores results" do
|
15
15
|
within_construct do |container|
|
16
|
-
container.file('tmp/aaa.json', '{"churn":{"changes":[{"file_path":".gitignore","times_changed":2},{"file_path":"lib\/churn.rb","times_changed":2},{"file_path":"Rakefile","times_changed":2},{"file_path":"README.rdoc","times_changed":2},{"file_path":"lib\/churn\/source_control.rb","times_changed":1},{"file_path":"lib\/churn\/svn_analyzer.rb","times_changed":1},{"file_path":"lib\/tasks\/churn_tasks.rb","times_changed":1},{"file_path":"LICENSE","times_changed":1},{"file_path":"test\/churn_test.rb","times_changed":1},{"file_path":"lib\/churn\/locationmapping.rb","times_changed":1},{"file_path":"lib\/churn\/git_analyzer.rb","times_changed":1},{"file_path":".document","times_changed":1},{"file_path":"test\/test_helper.rb","times_changed":1},{"file_path":"lib\/churn\/churn_calculator.rb","times_changed":1}],"method_churn":[],"changed_files":[".gitignore","lib\/churn\/source_control.rb","lib\/tasks\/churn_tasks.rb","lib\/churn\/svn_analyzer.rb","Rakefile","README.rdoc","lib\/churn\/locationmapping.rb","lib\/churn\/git_analyzer.rb","\/dev\/null","lib\/churn\/churn_calculator.rb","lib\/churn.rb"],"class_churn":[],"changed_classes":[{"klass":"ChurnTest","file":"test\/churn_test.rb"},{"klass":"ChurnCalculator","file":"lib\/churn\/churn_calculator.rb"}],"changed_methods":[{"klass":"","method":"#report_churn","file":"lib\/tasks\/churn_tasks.rb"}]}}')
|
16
|
+
container.file('tmp/churn/aaa.json', '{"churn":{"changes":[{"file_path":".gitignore","times_changed":2},{"file_path":"lib\/churn.rb","times_changed":2},{"file_path":"Rakefile","times_changed":2},{"file_path":"README.rdoc","times_changed":2},{"file_path":"lib\/churn\/source_control.rb","times_changed":1},{"file_path":"lib\/churn\/svn_analyzer.rb","times_changed":1},{"file_path":"lib\/tasks\/churn_tasks.rb","times_changed":1},{"file_path":"LICENSE","times_changed":1},{"file_path":"test\/churn_test.rb","times_changed":1},{"file_path":"lib\/churn\/locationmapping.rb","times_changed":1},{"file_path":"lib\/churn\/git_analyzer.rb","times_changed":1},{"file_path":".document","times_changed":1},{"file_path":"test\/test_helper.rb","times_changed":1},{"file_path":"lib\/churn\/churn_calculator.rb","times_changed":1}],"method_churn":[],"changed_files":[".gitignore","lib\/churn\/source_control.rb","lib\/tasks\/churn_tasks.rb","lib\/churn\/svn_analyzer.rb","Rakefile","README.rdoc","lib\/churn\/locationmapping.rb","lib\/churn\/git_analyzer.rb","\/dev\/null","lib\/churn\/churn_calculator.rb","lib\/churn.rb"],"class_churn":[],"changed_classes":[{"klass":"ChurnTest","file":"test\/churn_test.rb"},{"klass":"ChurnCalculator","file":"lib\/churn\/churn_calculator.rb"}],"changed_methods":[{"klass":"","method":"#report_churn","file":"lib\/tasks\/churn_tasks.rb"}]}}')
|
17
17
|
changed_files, changed_classes, changed_methods = Churn::ChurnHistory.load_revision_data('aaa')
|
18
18
|
assert changed_files.include?("lib/churn/source_control.rb")
|
19
19
|
assert_equal 2, changed_classes.length
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('../test_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class ChurnOptionsTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
should "store get default directory" do
|
6
|
+
assert_equal Churn::ChurnOptions::DEFAULT_CHURN_DIRECTORY, Churn::ChurnOptions.instance.data_directory
|
7
|
+
end
|
8
|
+
|
9
|
+
should "store get over ride directory" do
|
10
|
+
options = Churn::ChurnOptions.instance
|
11
|
+
tmp_dir = '/tmp/fake'
|
12
|
+
options.set_options({:data_directory => tmp_dir})
|
13
|
+
assert_equal tmp_dir, Churn::ChurnOptions.instance.data_directory
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: churn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 35
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 30
|
10
|
+
version: 0.0.30
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Dan Mayer
|
@@ -208,6 +208,7 @@ files:
|
|
208
208
|
- lib/churn/source_control.rb
|
209
209
|
- lib/churn/svn_analyzer.rb
|
210
210
|
- lib/churn/version.rb
|
211
|
+
- lib/churn_options.rb
|
211
212
|
- lib/tasks/churn_tasks.rb
|
212
213
|
- man/churn.1
|
213
214
|
- man/churn.html
|
@@ -217,6 +218,7 @@ files:
|
|
217
218
|
- test/unit/bzr_analyzer_test.rb
|
218
219
|
- test/unit/churn_calculator_test.rb
|
219
220
|
- test/unit/churn_history_test.rb
|
221
|
+
- test/unit/churn_options_test.rb
|
220
222
|
- test/unit/git_analyzer_test.rb
|
221
223
|
- test/unit/hg_analyzer_test.rb
|
222
224
|
- test/unit/location_mapping_test.rb
|
@@ -260,6 +262,7 @@ test_files:
|
|
260
262
|
- test/unit/bzr_analyzer_test.rb
|
261
263
|
- test/unit/churn_calculator_test.rb
|
262
264
|
- test/unit/churn_history_test.rb
|
265
|
+
- test/unit/churn_options_test.rb
|
263
266
|
- test/unit/git_analyzer_test.rb
|
264
267
|
- test/unit/hg_analyzer_test.rb
|
265
268
|
- test/unit/location_mapping_test.rb
|