revolutionhealth-metricks 0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +22 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +28 -0
- data/README +98 -0
- data/TODO.txt +4 -0
- data/lib/metricks/flog_reporter/base.rb +59 -0
- data/lib/metricks/flog_reporter/flog_reporter.css +39 -0
- data/lib/metricks/flog_reporter/generator.rb +71 -0
- data/lib/metricks/flog_reporter/operator.rb +10 -0
- data/lib/metricks/flog_reporter/page.rb +36 -0
- data/lib/metricks/flog_reporter/scanned_method.rb +28 -0
- data/lib/metricks/flog_reporter.rb +5 -0
- data/lib/metricks/md5_tracker.rb +52 -0
- data/lib/metricks/saikuro/SAIKURO_README +142 -0
- data/lib/metricks/saikuro/saikuro.rb +1216 -0
- data/lib/metricks.rb +7 -0
- data/lib/tasks/churn.rake +95 -0
- data/lib/tasks/coverage.rake +36 -0
- data/lib/tasks/flog.rake +58 -0
- data/lib/tasks/metricks.rake +11 -0
- data/lib/tasks/metricks.rb +6 -0
- data/lib/tasks/saikuro.rake +33 -0
- data/lib/tasks/stats.rake +14 -0
- data/metricks.gemspec +16 -0
- data/test/test_helper.rb +6 -0
- data/test/test_md5_tracker.rb +59 -0
- metadata +85 -0
data/lib/metricks.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
module Metricks
|
2
|
+
BASE_DIRECTORY = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metricks'
|
3
|
+
end
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), 'metricks', 'md5_tracker')
|
6
|
+
require File.join(File.dirname(__FILE__), 'metricks', 'flog_reporter')
|
7
|
+
require File.join(File.dirname(__FILE__), 'tasks', 'metricks')
|
@@ -0,0 +1,95 @@
|
|
1
|
+
namespace :metricks do
|
2
|
+
CHURN_DIR = File.join(Metricks::BASE_DIRECTORY, 'churn')
|
3
|
+
|
4
|
+
desc "Which files change the most"
|
5
|
+
task :churn do
|
6
|
+
date_range, minimum_churn_count = churn_options()
|
7
|
+
svn_logs = `svn log #{date_range} --verbose`.split(/\n/).select {|line| line.strip =~ /^[A,M]/}
|
8
|
+
|
9
|
+
changes = {}
|
10
|
+
svn_logs.each do |line|
|
11
|
+
line.strip =~ /^[A,M] (.*)/
|
12
|
+
changes[$1] ? changes[$1] += 1 : changes[$1] = 1
|
13
|
+
end
|
14
|
+
write_churn_file(changes.reject {|file, change_count| change_count < minimum_churn_count})
|
15
|
+
system("open #{CHURN_DIR}/index.html") if PLATFORM['darwin']
|
16
|
+
end
|
17
|
+
|
18
|
+
def churn_options
|
19
|
+
options = defined?(CHURN_OPTIONS) ? CHURN_OPTIONS : {}
|
20
|
+
if options[:start_date]
|
21
|
+
require File.dirname(__FILE__) + '/../../../../config/environment'
|
22
|
+
date_range = "--revision {#{options[:start_date].call.strftime('%Y-%m-%d')}}:{#{Time.now.strftime('%Y-%m-%d')}}"
|
23
|
+
else
|
24
|
+
date_range = ""
|
25
|
+
end
|
26
|
+
minimum_churn_count = options[:minimum_churn_count] ? options[:minimum_churn_count] : 5
|
27
|
+
return date_range, minimum_churn_count
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_churn_file changes
|
31
|
+
FileUtils.mkdir_p(CHURN_DIR, :verbose => false) unless File.directory?(CHURN_DIR)
|
32
|
+
File.open("#{CHURN_DIR}/index.html", "w+") do |file|
|
33
|
+
file << CHURN_FILE_BEGINING
|
34
|
+
changes.to_a.sort {|x,y| y[1] <=> x[1]}.each do |change|
|
35
|
+
file << "<tr><td>#{change[0]}</td><td class='warning'>#{change[1]}</td></tr>\n"
|
36
|
+
end
|
37
|
+
file << CHURN_FILE_END
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
CHURN_FILE_BEGINING = <<-EOS
|
42
|
+
<html><head><title>Source Control Churn Results</title></head>
|
43
|
+
<style>
|
44
|
+
body {
|
45
|
+
margin: 20px;
|
46
|
+
padding: 0;
|
47
|
+
font-size: 12px;
|
48
|
+
font-family: bitstream vera sans, verdana, arial, sans serif;
|
49
|
+
background-color: #efefef;
|
50
|
+
}
|
51
|
+
|
52
|
+
table {
|
53
|
+
border-collapse: collapse;
|
54
|
+
/*border-spacing: 0;*/
|
55
|
+
border: 1px solid #666;
|
56
|
+
background-color: #fff;
|
57
|
+
margin-bottom: 20px;
|
58
|
+
}
|
59
|
+
|
60
|
+
table, th, th+th, td, td+td {
|
61
|
+
border: 1px solid #ccc;
|
62
|
+
}
|
63
|
+
|
64
|
+
table th {
|
65
|
+
font-size: 12px;
|
66
|
+
color: #fc0;
|
67
|
+
padding: 4px 0;
|
68
|
+
background-color: #336;
|
69
|
+
}
|
70
|
+
|
71
|
+
th, td {
|
72
|
+
padding: 4px 10px;
|
73
|
+
}
|
74
|
+
|
75
|
+
td {
|
76
|
+
font-size: 13px;
|
77
|
+
}
|
78
|
+
|
79
|
+
.warning {
|
80
|
+
background-color: yellow;
|
81
|
+
}
|
82
|
+
</style>
|
83
|
+
|
84
|
+
<body>
|
85
|
+
<h1>Source Control Churn Results</h1>
|
86
|
+
<table width="100%" border="1">
|
87
|
+
<tr><th>File Path</th><th>Times Changed</th></tr>
|
88
|
+
EOS
|
89
|
+
|
90
|
+
CHURN_FILE_END = <<-EOS
|
91
|
+
</table>
|
92
|
+
</body>
|
93
|
+
</html>
|
94
|
+
EOS
|
95
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
namespace :metricks do
|
4
|
+
|
5
|
+
COVERAGE_DIR = File.join(Metricks::BASE_DIRECTORY, 'coverage')
|
6
|
+
COVERAGE_DATA_FILE = File.join(COVERAGE_DIR, "coverage.data")
|
7
|
+
|
8
|
+
desc "A coverage report using rcov"
|
9
|
+
task :coverage do
|
10
|
+
FileUtils.rm_rf(COVERAGE_DATA_FILE, :verbose => false) if File.exist?(COVERAGE_DATA_FILE)
|
11
|
+
FileUtils.mkdir_p(COVERAGE_DIR) unless File.directory?(COVERAGE_DIR)
|
12
|
+
paths = defined?(TEST_PATHS_FOR_RCOV) ? TEST_PATHS_FOR_RCOV : ['test/**/*_test.rb']
|
13
|
+
paths.each { |path| execute_rcov(path) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute_rcov(test_list)
|
17
|
+
default_options = {"--rails" => "",
|
18
|
+
"--aggregate" => "#{File.join(COVERAGE_DIR, 'coverage.data')}",
|
19
|
+
"--sort" => "coverage",
|
20
|
+
"--exclude" => '"gems/*,rcov*,spec/*,test/*"',
|
21
|
+
"--output" => %["#{COVERAGE_DIR}"]}
|
22
|
+
|
23
|
+
default_options.merge!(RCOV_OPTIONS) if defined?(RCOV_OPTIONS)
|
24
|
+
options = ""
|
25
|
+
default_options.each_pair { |key, value| options << "#{key} #{value} " }
|
26
|
+
|
27
|
+
sh "rcov #{options} #{test_list}" do |ok, response|
|
28
|
+
unless ok
|
29
|
+
puts "Rcov failed with exit status: #{response.exitstatus}"
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
system("open #{COVERAGE_DIR}/index.html") if PLATFORM['darwin']
|
35
|
+
end
|
36
|
+
end
|
data/lib/tasks/flog.rake
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'metricks/md5_tracker'
|
2
|
+
require 'metricks/flog_reporter'
|
3
|
+
|
4
|
+
begin
|
5
|
+
FLOG_DIR = File.join(Metricks::BASE_DIRECTORY, 'flog')
|
6
|
+
|
7
|
+
def flog(output, directory)
|
8
|
+
Dir.glob("#{directory}/**/*.rb").each do |filename|
|
9
|
+
output_dir = "#{FLOG_DIR}/#{filename.split("/")[0..-2].join("/")}"
|
10
|
+
mkdir_p(output_dir, :verbose => false) unless File.directory?(output_dir)
|
11
|
+
`flog #{filename} > #{FLOG_DIR}/#{filename.split('.')[0]}.txt` if Metricks::MD5Tracker.file_changed?(filename, FLOG_DIR)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :metricks do
|
16
|
+
|
17
|
+
task :flog => ['flog:all'] do
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :flog do
|
21
|
+
desc "Delete aggregate flog data."
|
22
|
+
task(:clean) { rm_rf(FLOG_DIR, :verbose => false) }
|
23
|
+
|
24
|
+
desc "Flog code in app/models"
|
25
|
+
task :models do
|
26
|
+
flog "models", "app/models"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Flog code in app/controllers"
|
30
|
+
task :controllers do
|
31
|
+
flog "controllers", "app/controllers"
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Flog code in app/helpers"
|
35
|
+
task :helpers do
|
36
|
+
flog "helpers", "app/helpers"
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Flog code in lib"
|
40
|
+
task :lib do
|
41
|
+
flog "lib", "lib"
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Generate and open flog report"
|
45
|
+
task :all => [:models, :controllers, :helpers, :lib] do
|
46
|
+
Metricks::FlogReporter::Generator.generate_report(FLOG_DIR)
|
47
|
+
system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
rescue LoadError
|
53
|
+
if RUBY_PLATFORM =~ /java/
|
54
|
+
puts 'running in jruby - flog tasks not available'
|
55
|
+
else
|
56
|
+
puts 'sudo gem install flog # if you want the flog tasks'
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :metricks do
|
2
|
+
task :prepare do
|
3
|
+
RAILS_ENV = 'test'
|
4
|
+
end
|
5
|
+
|
6
|
+
desc "Useful for continuous integration"
|
7
|
+
task :all_with_migrate => [:prepare, "db:migrate", :all]
|
8
|
+
|
9
|
+
desc "Generate coverage, cyclomatic complexity (saikuro), flog, stats, and churn reports"
|
10
|
+
task :all => [:coverage, :saikuro, :flog, :churn, :stats]
|
11
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
namespace :metricks do
|
2
|
+
|
3
|
+
SAIKURO_DIR = File.join(Metricks::BASE_DIRECTORY, 'saikuro')
|
4
|
+
|
5
|
+
desc "A cyclomatic complexity report using Saikuro"
|
6
|
+
task :saikuro do
|
7
|
+
default_options = {"--output_directory" => SAIKURO_DIR,
|
8
|
+
"--input_directory" => "app",
|
9
|
+
"--cyclo" => "",
|
10
|
+
"--filter_cyclo" => "0",
|
11
|
+
"--warn_cyclo" => "5",
|
12
|
+
"--error_cyclo" => "7"}
|
13
|
+
|
14
|
+
default_options.merge!(SAIKURO_OPTIONS) if defined?(SAIKURO_OPTIONS)
|
15
|
+
options = ""
|
16
|
+
default_options.each_pair { |key, value| options << "#{key} #{value} " }
|
17
|
+
|
18
|
+
sh "ruby #{File.expand_path(File.join(File.dirname(__FILE__), '..', 'metricks', 'saikuro'))}/saikuro.rb " +
|
19
|
+
"#{options}" do |ok, response|
|
20
|
+
unless ok
|
21
|
+
puts "Saikuro failed with exit status: #{response.exitstatus}"
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if File.exist? "#{SAIKURO_DIR}/index_cyclo.html"
|
27
|
+
mv "#{SAIKURO_DIR}/index_cyclo.html",
|
28
|
+
"#{SAIKURO_DIR}/index.html"
|
29
|
+
end
|
30
|
+
|
31
|
+
system("open #{SAIKURO_DIR}/index.html") if PLATFORM['darwin']
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
namespace :metricks do
|
2
|
+
|
3
|
+
STATS_DIR = File.join(Metricks::BASE_DIRECTORY, 'stats')
|
4
|
+
STATS_FILE = File.join(STATS_DIR, 'index.html')
|
5
|
+
|
6
|
+
desc "A stats report"
|
7
|
+
task :stats do
|
8
|
+
mkdir_p(STATS_DIR) unless File.directory?(STATS_DIR)
|
9
|
+
`echo '<pre>' > #{STATS_FILE}`
|
10
|
+
`rake stats >> #{STATS_FILE}`
|
11
|
+
`echo '</pre>' >> #{STATS_FILE}`
|
12
|
+
system("open #{STATS_FILE}") if PLATFORM['darwin']
|
13
|
+
end
|
14
|
+
end
|
data/metricks.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "metricks"
|
3
|
+
s.version = "0.4"
|
4
|
+
s.date = "2008-06-13"
|
5
|
+
s.summary = "Generates project metrics using Flog, RCov, Saikuro and more"
|
6
|
+
s.email = "sean.soper@gmail.com"
|
7
|
+
s.homepage = "http://github.com/revolutionhealth/metricks"
|
8
|
+
s.description = "Metricks is a fork of the metric_fu project and adds support for additional code analysis tools"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Sean Soper"]
|
11
|
+
s.files = %w(History.txt Manifest.txt metricks.gemspec MIT-LICENSE README TODO.txt) + Dir.glob("{lib,test}/**/*")
|
12
|
+
s.test_files = ["test/test_md5_tracker.rb"]
|
13
|
+
s.rdoc_options = ["--main", "README"]
|
14
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README"]
|
15
|
+
# s.add_dependency("mime-types", ["> 0.0.0"])
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class TestMD5Tracker < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
|
7
|
+
FileUtils.mkdir_p(@tmp_dir, :verbose => false) unless File.directory?(@tmp_dir)
|
8
|
+
@file1 = File.new(File.join(@tmp_dir, 'file1.txt'), 'w')
|
9
|
+
@file2 = File.new(File.join(@tmp_dir, 'file2.txt'), 'w')
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
FileUtils.rm_rf(@tmp_dir, :verbose => false)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_identical_files_match
|
17
|
+
@file1.puts("Hello World")
|
18
|
+
@file1.close
|
19
|
+
file1_md5 = Metricks::MD5Tracker.track(@file1.path, @tmp_dir)
|
20
|
+
|
21
|
+
@file2.puts("Hello World")
|
22
|
+
@file2.close
|
23
|
+
file2_md5 = Metricks::MD5Tracker.track(@file2.path, @tmp_dir)
|
24
|
+
|
25
|
+
assert file1_md5 == file2_md5
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_different_files_dont_match
|
29
|
+
@file1.puts("Hello World")
|
30
|
+
@file1.close
|
31
|
+
file1_md5 = Metricks::MD5Tracker.track(@file1.path, @tmp_dir)
|
32
|
+
|
33
|
+
@file2.puts("Goodbye World")
|
34
|
+
@file2.close
|
35
|
+
file2_md5 = Metricks::MD5Tracker.track(@file2.path, @tmp_dir)
|
36
|
+
|
37
|
+
assert file1_md5 != file2_md5
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_file_changed
|
41
|
+
@file2.close
|
42
|
+
|
43
|
+
@file1.puts("Hello World")
|
44
|
+
@file1.close
|
45
|
+
file1_md5 = Metricks::MD5Tracker.track(@file1.path, @tmp_dir)
|
46
|
+
|
47
|
+
@file1 = File.new(File.join(@tmp_dir, 'file1.txt'), 'w')
|
48
|
+
@file1.puts("Goodbye World")
|
49
|
+
@file1.close
|
50
|
+
assert Metricks::MD5Tracker.file_changed?(@file1.path, @tmp_dir)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_file_changed_if_not_tracking
|
54
|
+
@file2.close
|
55
|
+
|
56
|
+
assert Metricks::MD5Tracker.file_changed?(@file1.path, @tmp_dir)
|
57
|
+
assert File.exist?(Metricks::MD5Tracker.md5_file(@file1.path, @tmp_dir))
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: revolutionhealth-metricks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.4"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Soper
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-06-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Metricks is a fork of the metric_fu project and adds support for additional code analysis tools
|
17
|
+
email: sean.soper@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- History.txt
|
24
|
+
- Manifest.txt
|
25
|
+
- README
|
26
|
+
files:
|
27
|
+
- History.txt
|
28
|
+
- Manifest.txt
|
29
|
+
- metricks.gemspec
|
30
|
+
- MIT-LICENSE
|
31
|
+
- README
|
32
|
+
- TODO.txt
|
33
|
+
- lib/metricks
|
34
|
+
- lib/metricks/saikuro
|
35
|
+
- lib/metricks/saikuro/SAIKURO_README
|
36
|
+
- lib/metricks/saikuro/saikuro.rb
|
37
|
+
- lib/metricks/flog_reporter.rb
|
38
|
+
- lib/metricks/flog_reporter
|
39
|
+
- lib/metricks/flog_reporter/scanned_method.rb
|
40
|
+
- lib/metricks/flog_reporter/generator.rb
|
41
|
+
- lib/metricks/flog_reporter/flog_reporter.css
|
42
|
+
- lib/metricks/flog_reporter/base.rb
|
43
|
+
- lib/metricks/flog_reporter/page.rb
|
44
|
+
- lib/metricks/flog_reporter/operator.rb
|
45
|
+
- lib/metricks/md5_tracker.rb
|
46
|
+
- lib/tasks
|
47
|
+
- lib/tasks/flog.rake
|
48
|
+
- lib/tasks/metricks.rb
|
49
|
+
- lib/tasks/metricks.rake
|
50
|
+
- lib/tasks/coverage.rake
|
51
|
+
- lib/tasks/churn.rake
|
52
|
+
- lib/tasks/saikuro.rake
|
53
|
+
- lib/tasks/stats.rake
|
54
|
+
- lib/metricks.rb
|
55
|
+
- test/test_md5_tracker.rb
|
56
|
+
- test/test_helper.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/revolutionhealth/metricks
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --main
|
62
|
+
- README
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.0.1
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: Generates project metrics using Flog, RCov, Saikuro and more
|
84
|
+
test_files:
|
85
|
+
- test/test_md5_tracker.rb
|