aidir 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/aidir +5 -0
- data/lib/aidir.rb +35 -0
- data/lib/aidir/flog.rb +75 -0
- data/lib/aidir/git.rb +62 -0
- data/lib/aidir/scoreboard.rb +195 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7742d491ef0024bf96b42dc5702247322aa561cd
|
4
|
+
data.tar.gz: 77c3484dff8c9d897fec772ab81c39824c2b5bfd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a567fe9d09b8326ba6458f25c6933564c1f831ab6deb118f5711a6fb387585fd70190d55544ed3f8e2cb0c6985194c0ddd7487497ac52242d0e8c31e818e800
|
7
|
+
data.tar.gz: 4816f092e78393dac48ea363ef4dffea115d70583f71eb34926f8c44b4401172bfcc96a7a6a6facacf6bc6ace49e1d2a9e53346e0795fc00717fa480657dd88b
|
data/bin/aidir
ADDED
data/lib/aidir.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'aidir/git'
|
2
|
+
require_relative 'aidir/flog'
|
3
|
+
require_relative 'aidir/scoreboard'
|
4
|
+
require 'open3'
|
5
|
+
|
6
|
+
class Aidir
|
7
|
+
|
8
|
+
def self.start
|
9
|
+
@errors = []
|
10
|
+
@results = {}
|
11
|
+
git = nil
|
12
|
+
files = nil
|
13
|
+
|
14
|
+
git = Git.new(@errors)
|
15
|
+
git.is_repository?
|
16
|
+
if @errors.any?
|
17
|
+
puts @errors
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
files = git.ruby_files
|
22
|
+
|
23
|
+
files.each do |file|
|
24
|
+
flog = Flog.new(file)
|
25
|
+
@results[file] = flog.analyze
|
26
|
+
end
|
27
|
+
|
28
|
+
git.clear_cached_files
|
29
|
+
|
30
|
+
scoreboard = Scoreboard.new(@results)
|
31
|
+
output = scoreboard.results
|
32
|
+
print output
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/aidir/flog.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
class Flog
|
2
|
+
|
3
|
+
def initialize(filename)
|
4
|
+
@branch = filename
|
5
|
+
@master = temp(filename)
|
6
|
+
@flog_data = {}
|
7
|
+
@results = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def analyze
|
11
|
+
flog_both
|
12
|
+
parse_flog_data
|
13
|
+
@results
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def flog_both
|
19
|
+
@flog_data[:branch] = flog_file(@branch)
|
20
|
+
@flog_data[:master] = flog_file(@master)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_flog_data
|
24
|
+
@flog_data.each do |branch, branch_data|
|
25
|
+
data = raw_to_hash(branch_data)
|
26
|
+
data.each do |key, val|
|
27
|
+
@results[key] ||= {}
|
28
|
+
@results[key][branch] = val
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def flog_file(filename)
|
34
|
+
Open3.popen3("flog -a #{filename}") do |_, stdout, stderr|
|
35
|
+
stdout.read
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def raw_to_hash(data)
|
40
|
+
lines = string_to_line_arr(data)
|
41
|
+
lines = values_to_floats(lines)
|
42
|
+
lines[2..-1] = clean_method_names(lines[2..-1]) # clean methods from paths
|
43
|
+
Hash[*lines.flatten]
|
44
|
+
end
|
45
|
+
|
46
|
+
def temp(file)
|
47
|
+
safe_filename = file.gsub('/', '_')
|
48
|
+
"#{Dir.pwd}/tmp/aidir_#{safe_filename}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def string_to_line_arr(string)
|
52
|
+
string.split("\n")
|
53
|
+
.reject { |l| l.empty? }
|
54
|
+
.map! { |l| l.strip.split(": ").reverse }
|
55
|
+
end
|
56
|
+
|
57
|
+
def values_to_floats(lines)
|
58
|
+
lines.map do |line|
|
59
|
+
[
|
60
|
+
line[0],
|
61
|
+
line[1].to_f
|
62
|
+
]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def clean_method_names(lines)
|
67
|
+
lines.map do |line|
|
68
|
+
[
|
69
|
+
line[0].split.first,
|
70
|
+
line[1]
|
71
|
+
]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/lib/aidir/git.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
class Git
|
2
|
+
|
3
|
+
def initialize(errors)
|
4
|
+
@errors = errors
|
5
|
+
@changed_files = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def is_repository?
|
9
|
+
error = false
|
10
|
+
Open3.popen3('git rev-parse') do |_, _, stderr|
|
11
|
+
error = stderr.read
|
12
|
+
@errors << error unless error.empty?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def ruby_files
|
17
|
+
all_changed_files
|
18
|
+
filter_ruby_files
|
19
|
+
cache_files
|
20
|
+
@changed_files
|
21
|
+
end
|
22
|
+
|
23
|
+
def clear_cached_files
|
24
|
+
@changed_files.each do |file|
|
25
|
+
File.delete(temp(file))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def all_changed_files
|
32
|
+
Open3.popen3("git diff --name-only origin/master...") do |_, stdout, stderr|
|
33
|
+
out = stdout.read
|
34
|
+
@changed_files = out.split("\n") unless out.empty?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def filter_ruby_files
|
39
|
+
@changed_files.reject! { |filename| filename[-3..-1] != '.rb' }
|
40
|
+
end
|
41
|
+
|
42
|
+
def cache_files
|
43
|
+
@changed_files.each do |file|
|
44
|
+
File.open(temp(file), 'w') do |f|
|
45
|
+
f.write(remote_file_contents(file))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def remote_file_contents(file)
|
51
|
+
Open3.popen3("git show origin/master:#{file}") do |_, stdout, stderr|
|
52
|
+
stdout.read
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def temp(file)
|
57
|
+
safe_filename = file.gsub('/', '_')
|
58
|
+
"#{Dir.pwd}/tmp/aidir_#{safe_filename}"
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
class Scoreboard
|
2
|
+
|
3
|
+
def initialize(raw_data)
|
4
|
+
@raw_data = raw_data
|
5
|
+
@diff_data = {}
|
6
|
+
@file_data = {}
|
7
|
+
@method_data = {}
|
8
|
+
@output = ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def results
|
12
|
+
get_relevant_scores
|
13
|
+
if @method_data.empty?
|
14
|
+
print_no_diffs
|
15
|
+
return
|
16
|
+
end
|
17
|
+
print_method_board
|
18
|
+
print_file_board
|
19
|
+
@output
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def get_relevant_scores
|
25
|
+
get_diffs
|
26
|
+
split_scores_by_type
|
27
|
+
sort_scores
|
28
|
+
end
|
29
|
+
|
30
|
+
def diff_format
|
31
|
+
@diff_format ||= "%s%18.1f%s"
|
32
|
+
end
|
33
|
+
|
34
|
+
def current_format
|
35
|
+
@current_format ||= "%s%10.1f%s"
|
36
|
+
end
|
37
|
+
|
38
|
+
def diff_output(score)
|
39
|
+
sprintf(diff_format, diff_prefix(score), score, color_end)
|
40
|
+
end
|
41
|
+
|
42
|
+
def current_output(score)
|
43
|
+
sprintf(current_format, current_prefix(score), score, color_end)
|
44
|
+
end
|
45
|
+
|
46
|
+
def total_current_output(score)
|
47
|
+
sprintf(current_format, "", score, "")
|
48
|
+
end
|
49
|
+
|
50
|
+
def avg_current_output(score)
|
51
|
+
sprintf(current_format, current_prefix(score), score, color_end)
|
52
|
+
end
|
53
|
+
|
54
|
+
def head_format
|
55
|
+
@head_format ||= "%18s%10s %-90s\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
def print_method_board
|
59
|
+
@output << "--- #{cyan_start}METHOD SCORES#{color_end} ---\n"
|
60
|
+
|
61
|
+
@output << sprintf(head_format, "Diff from master", "Current", "Method")
|
62
|
+
format = "%s%s %-90s\n"
|
63
|
+
|
64
|
+
@method_data.each do |method, info|
|
65
|
+
current = info[:current]
|
66
|
+
unless info[:flag]
|
67
|
+
diff = info[:diff]
|
68
|
+
@output << sprintf(format, diff_output(diff), current_output(current), method)
|
69
|
+
else
|
70
|
+
flag_output = sprintf("%18s", info[:flag].to_s)
|
71
|
+
@output << sprintf(format, flag_output, current_output(current), method)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def print_file_board
|
77
|
+
@output << "--- #{cyan_start}FILE SCORES#{color_end} ---\n"
|
78
|
+
|
79
|
+
@output << sprintf(head_format, "Diff from master", "Current", "Method")
|
80
|
+
format = "%s%s %-90s\n"
|
81
|
+
|
82
|
+
@file_data.each do |metric, files|
|
83
|
+
@output << sprintf("%-18s\n", "#{cyan_start}#{metric}#{color_end}")
|
84
|
+
files.each do |file|
|
85
|
+
filename = file[:file]
|
86
|
+
diff = file[:diff]
|
87
|
+
current = file[:current]
|
88
|
+
if metric == "flog total"
|
89
|
+
@output << sprintf(format, diff_output(diff), total_current_output(current), filename)
|
90
|
+
else
|
91
|
+
@output << sprintf(format, diff_output(diff), avg_current_output(current), filename)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def print_no_diffs
|
98
|
+
@output << "#{cyan_start}No changes detected#{color_end}\n"
|
99
|
+
end
|
100
|
+
|
101
|
+
def diff_prefix(score)
|
102
|
+
if score < 0
|
103
|
+
green_start
|
104
|
+
elsif score < 5
|
105
|
+
yellow_start
|
106
|
+
else
|
107
|
+
red_start
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def current_prefix(score)
|
112
|
+
if score < 20
|
113
|
+
green_start
|
114
|
+
elsif score < 40
|
115
|
+
yellow_start
|
116
|
+
else
|
117
|
+
red_start
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def cyan_start
|
122
|
+
"\033[36m"
|
123
|
+
end
|
124
|
+
|
125
|
+
def red_start
|
126
|
+
"\033[31m"
|
127
|
+
end
|
128
|
+
|
129
|
+
def yellow_start
|
130
|
+
"\033[33m"
|
131
|
+
end
|
132
|
+
|
133
|
+
def green_start
|
134
|
+
"\033[32m"
|
135
|
+
end
|
136
|
+
|
137
|
+
def color_end
|
138
|
+
"\033[0m"
|
139
|
+
end
|
140
|
+
|
141
|
+
def split_scores_by_type
|
142
|
+
@method_data = @diff_data
|
143
|
+
file_keys.each do |key|
|
144
|
+
@file_data[key] = @method_data.delete(key)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def get_diffs
|
149
|
+
@raw_data.each do |file, lines|
|
150
|
+
lines.each do |metric, scores|
|
151
|
+
score = diff(scores[:branch], scores[:master])
|
152
|
+
next if score == 0.0
|
153
|
+
@diff_data[metric] ||= []
|
154
|
+
flag = nil
|
155
|
+
if [:new, :deleted].include?(score)
|
156
|
+
flag = score
|
157
|
+
score = 0.0
|
158
|
+
end
|
159
|
+
@diff_data[metric] << {
|
160
|
+
file: file,
|
161
|
+
diff: score,
|
162
|
+
current: scores[:branch],
|
163
|
+
flag: flag
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def sort_scores
|
170
|
+
return if @method_data.empty?
|
171
|
+
file_keys.each do |key|
|
172
|
+
@file_data[key].sort_by! { |f| -f[:diff] }
|
173
|
+
end
|
174
|
+
sorted_methods = @method_data.sort_by { |_, data| -data[0][:diff] }.flatten
|
175
|
+
@method_data = Hash[*sorted_methods]
|
176
|
+
end
|
177
|
+
|
178
|
+
def diff(branch, master)
|
179
|
+
if master and branch
|
180
|
+
(branch - master).round(2)
|
181
|
+
elsif branch
|
182
|
+
:new
|
183
|
+
else
|
184
|
+
:deleted
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def file_keys
|
189
|
+
[
|
190
|
+
'flog total',
|
191
|
+
'flog/method average'
|
192
|
+
]
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aidir
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adomas Sliužinskas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: flog
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.1.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.1.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: flog
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.1.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.1.2
|
41
|
+
description: 'aidir - Am I Doing It Right: track and improve your Flog (http://ruby.sadi.st/Flog.html)
|
42
|
+
score before merging code to master by getting Flog score differences between current
|
43
|
+
branch and master branch'
|
44
|
+
email: adomas.sliuzinskas@gmail.com
|
45
|
+
executables:
|
46
|
+
- aidir
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- lib/aidir.rb
|
51
|
+
- lib/aidir/flog.rb
|
52
|
+
- lib/aidir/git.rb
|
53
|
+
- lib/aidir/scoreboard.rb
|
54
|
+
- bin/aidir
|
55
|
+
homepage: http://github.com/adomas-s/aidir
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 2.0.3
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: Shows Flog score diff of current git branch vs. origin/master
|
79
|
+
test_files: []
|