2
2
3
3
require "json"
4
4
require "colorize"
5
+ require_relative "./codeclimate_wrapper"
6
+ require_relative "./result_printer"
7
+ require_relative "./issue_sorter"
5
8
6
9
module CodeclimateDiff
7
10
class Runner
8
- def self . generate_baseline
9
- puts "Generating the baseline. Should take about 5 minutes..."
10
- `codeclimate analyze -f json > codeclimate_diff_baseline.json`
11
- puts "Done!"
12
- end
13
-
14
11
def self . calculate_changed_filenames ( pattern )
15
12
extra_grep_filter = pattern ? " | grep '#{ pattern } '" : ""
16
13
files_changed = `git diff --name-only main | grep --invert-match spec/ | grep --extended-regexp '.js$|.rb$'#{ extra_grep_filter } `
@@ -24,7 +21,7 @@ def self.calculate_issues_in_changed_files(changed_filenames)
24
21
next if filename == "codeclimate_diff.rb" # TODO: fix this file's code quality issues when we make a Gem!
25
22
26
23
puts "Analysing '#{ filename } '..."
27
- result = `codeclimate analyze -f json #{ filename } `
24
+ result = CodeclimateWrapper . new . run_codeclimate ( filename )
28
25
JSON . parse ( result ) . each do |issue |
29
26
next if issue [ "type" ] != "issue"
30
27
@@ -42,160 +39,11 @@ def self.calculate_preexisting_issues_in_changed_files(changed_filenames)
42
39
all_issues . filter { |issue | issue . key? ( "location" ) && changed_filenames . include? ( issue [ "location" ] [ "path" ] ) }
43
40
end
44
41
45
- def self . remove_closest_match_from_list ( issue_to_match , list )
46
- # check for exact match first
47
- index = list . index do |issue |
48
- issue [ "fingerprint" ] == issue_to_match [ "fingerprint" ] &&
49
- issue [ "location" ] [ "lines" ] [ "begin" ] == issue_to_match [ "location" ] [ "lines" ] [ "begin" ] &&
50
- issue [ "description" ] == issue_to_match [ "description" ]
51
- end
52
-
53
- if index
54
- list . delete_at ( index )
55
- return
56
- end
57
-
58
- # check for same method name (description often has method name or variable name in it)
59
- index = list . index do |issue |
60
- issue [ "fingerprint" ] == issue_to_match [ "fingerprint" ] &&
61
- issue [ "description" ] == issue_to_match [ "description" ]
62
- end
63
-
64
- if index
65
- list . delete_at ( index )
66
- return
67
- end
68
-
69
- # otherwise just remove the first one
70
- list . pop
71
- end
72
-
73
- def self . sort_issues ( preexisting_issues , changed_file_issues )
74
- puts "Sorting into :preexisting, :new and :fixed lists..."
75
-
76
- result = { }
77
- result [ :preexisting ] = [ ]
78
- result [ :new ] = [ ]
79
- result [ :fixed ] = [ ]
80
-
81
- # fingerprints are unique per issue type and file
82
- # so there could be multiple if the same issue shows up multiple times
83
- # plus line numbers and method names could have changed
84
- unique_fingerprints = ( preexisting_issues + changed_file_issues ) . map { |issue | issue [ "fingerprint" ] } . uniq
85
-
86
- unique_fingerprints . each do |fingerprint |
87
- baseline_issues = preexisting_issues . filter { |issue | issue [ "fingerprint" ] == fingerprint }
88
- current_issues = changed_file_issues . filter { |issue | issue [ "fingerprint" ] == fingerprint }
89
-
90
- if baseline_issues . count == current_issues . count
91
- # current issues are most up to date (line numbers could have changed etc.)
92
- result [ :preexisting ] += current_issues
93
- elsif current_issues . count < baseline_issues . count
94
- # less issues than there were before
95
- current_issues . each do |issue_to_match |
96
- CodeclimateDiff . remove_closest_match_from_list ( issue_to_match , baseline_issues )
97
- end
98
- result [ :fixed ] += baseline_issues
99
- else
100
- # more issues than there were before
101
- baseline_issues . each do |issue_to_match |
102
- CodeclimateDiff . remove_closest_match_from_list ( issue_to_match , current_issues )
103
- end
104
- result [ :new ] += current_issues
105
- end
106
- end
107
-
108
- # do a check to make sure the maths works out
109
- puts "#{ preexisting_issues . count } issues in matching files in baseline"
110
- puts "#{ changed_file_issues . count } current issues in matching files"
111
-
112
- result
113
- end
114
-
115
- def self . print_issues_in_category ( issues_list )
116
- issues_list . each do |issue |
117
- filename = issue [ "location" ] [ "path" ]
118
- line_number = issue [ "location" ] [ "lines" ] [ "begin" ]
119
- description = issue [ "description" ]
120
-
121
- print "\u2022 #{ filename } :#{ line_number } " . encode ( "utf-8" ) . bold
122
- puts " #{ description } "
123
- end
124
- puts "\n "
125
- end
126
-
127
- def self . print_category ( bullet_emoji , severity , engine_name , check_name , color )
128
- message = "#{ bullet_emoji } [#{ severity } ] #{ engine_name } #{ check_name } :" . encode ( "utf-8" )
129
-
130
- case color
131
- when "red"
132
- puts message . red
133
- when "yellow"
134
- puts message . yellow
135
- when "green"
136
- puts message . green
137
- else
138
- puts message
139
- end
140
- end
141
-
142
- def self . print_issues ( issues_list , color , bullet_emoji )
143
- issue_categories = issues_list . map { |issue | [ issue [ "engine_name" ] , issue [ "check_name" ] , issue [ "severity" ] ] } . uniq
144
- issue_categories . each do |issue_category |
145
- engine_name = issue_category [ 0 ]
146
- check_name = issue_category [ 1 ]
147
- severity = issue_category [ 2 ]
148
- issues = issues_list . filter do |issue |
149
- issue [ "engine_name" ] == engine_name &&
150
- issue [ "check_name" ] == check_name &&
151
- issue [ "severity" ] == severity
152
- end
153
- print_category ( bullet_emoji , severity , engine_name , check_name , color )
154
- print_issues_in_category ( issues )
155
- end
156
- end
157
-
158
- def self . print_result ( sorted_issues , show_preexisting )
159
- if show_preexisting
160
- preexisting_issues = sorted_issues [ :preexisting ]
161
- if preexisting_issues . count . positive?
162
- puts "\n #{ preexisting_issues . count } preexisting issues in changed files:\n " . bold . yellow
163
- print_issues ( preexisting_issues , "yellow" , "\u2718 " )
164
- else
165
- puts "\n 0 issues in changed files!" . encode ( "utf-8" ) . bold . green
166
- end
167
- end
168
-
169
- new_issues = sorted_issues [ :new ]
170
- if new_issues . count . positive?
171
- puts "\n #{ new_issues . count } new issues:\n " . bold . red
172
- print_issues ( new_issues , "red" , "\u2718 " )
173
- else
174
- puts "\n 0 new issues :)\n " . encode ( "utf-8" ) . bold
175
- end
176
-
177
- fixed_issues = sorted_issues [ :fixed ]
178
- if fixed_issues . count . positive?
179
- puts "\n #{ fixed_issues . count } fixed issues: \n " . encode ( "utf-8" ) . bold . green
180
- print_issues ( fixed_issues , "green" , "\u2714 " )
181
- else
182
- puts "\n 0 fixed issues\n " . bold
183
- end
184
- end
185
-
186
- def self . print_call_to_action ( sorted_issues )
187
- fixed_count = sorted_issues [ :fixed ] . count
188
- new_count = sorted_issues [ :new ] . count
189
- outstanding_count = sorted_issues [ :preexisting ] . count + new_count
190
- if fixed_count > new_count
191
- puts "\n \u{1F389} \u{1F389} Well done! You made the code even better!! \u{1F389} \u{1F389} \n " . bold . green . encode ( "utf-8" )
192
- elsif new_count > fixed_count
193
- puts "\n \ Uh oh, you've introduced more issues than you've fixed. Better fix that! \n " . bold . red . encode ( "utf-8" )
194
- elsif outstanding_count . positive?
195
- puts "\n \ Why don't you see if you can fix some of those outstanding issues while you're here? \n " . bold . encode ( "utf-8" )
196
- else
197
- puts "\n \u{1F389} \u{1F389} Nothing to do here, the code is immaculate!! \u{1F389} \u{1F389} \n " . bold . green . encode ( "utf-8" )
198
- end
42
+ def self . generate_baseline
43
+ puts "Generating the baseline. Should take about 5 minutes..."
44
+ result = CodeclimateWrapper . new . run_codeclimate
45
+ File . write ( "codeclimate_diff_baseline.json" , result )
46
+ puts "Done!"
199
47
end
200
48
201
49
def self . run_diff_on_branch ( pattern , show_preexisting : true )
@@ -205,10 +53,10 @@ def self.run_diff_on_branch(pattern, show_preexisting: true)
205
53
206
54
preexisting_issues = calculate_preexisting_issues_in_changed_files ( changed_filenames )
207
55
208
- sorted_issues = sort_issues ( preexisting_issues , changed_file_issues )
56
+ sorted_issues = IssueSorter . sort_issues ( preexisting_issues , changed_file_issues )
209
57
210
- print_result ( sorted_issues , show_preexisting )
211
- print_call_to_action ( sorted_issues )
58
+ ResultPrinter . print_result ( sorted_issues , show_preexisting )
59
+ ResultPrinter . print_call_to_action ( sorted_issues )
212
60
end
213
61
end
214
62
end
0 commit comments