kwala 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/README +62 -0
  2. data/bin/kwala +39 -0
  3. data/lib/kwala.rb +59 -0
  4. data/lib/kwala/actions/code_change.rb +128 -0
  5. data/lib/kwala/actions/code_coverage.rb +303 -0
  6. data/lib/kwala/actions/code_duplication.rb +222 -0
  7. data/lib/kwala/actions/code_formatting.rb +358 -0
  8. data/lib/kwala/actions/cycle_detection.rb +118 -0
  9. data/lib/kwala/actions/cyclomatic_complexity.rb +159 -0
  10. data/lib/kwala/actions/dead_code.rb +68 -0
  11. data/lib/kwala/actions/executable_files_check.rb +111 -0
  12. data/lib/kwala/actions/flagged_comments.rb +128 -0
  13. data/lib/kwala/actions/gem_plugin.rb +31 -0
  14. data/lib/kwala/actions/loc_count.rb +153 -0
  15. data/lib/kwala/actions/multi_ruby_unit_test.rb +62 -0
  16. data/lib/kwala/actions/outside_links.rb +85 -0
  17. data/lib/kwala/actions/rails_migrate.rb +62 -0
  18. data/lib/kwala/actions/strange_requires.rb +106 -0
  19. data/lib/kwala/actions/syntax_check.rb +130 -0
  20. data/lib/kwala/actions/unit_test.rb +368 -0
  21. data/lib/kwala/build_action.rb +88 -0
  22. data/lib/kwala/build_context.rb +49 -0
  23. data/lib/kwala/command_line_runner.rb +184 -0
  24. data/lib/kwala/ext/demos.jar +0 -0
  25. data/lib/kwala/ext/pmd.jar +0 -0
  26. data/lib/kwala/ext/prefuse.jar +0 -0
  27. data/lib/kwala/extensions.rb +36 -0
  28. data/lib/kwala/lib/code_analyzer.rb +678 -0
  29. data/lib/kwala/lib/cycle_detector.rb +793 -0
  30. data/lib/kwala/lib/strange_requires_detector.rb +145 -0
  31. data/lib/kwala/notification.rb +45 -0
  32. data/lib/kwala/notifications/email.rb +54 -0
  33. data/lib/kwala/notifications/rss.rb +151 -0
  34. data/lib/kwala/project_builder_utils.rb +178 -0
  35. data/lib/kwala/templates/build_template.html +33 -0
  36. data/lib/kwala/templates/code_change_summary.html +27 -0
  37. data/lib/kwala/templates/code_coverage_detailed.html +25 -0
  38. data/lib/kwala/templates/code_coverage_summary.html +30 -0
  39. data/lib/kwala/templates/code_duplication_detailed.html +45 -0
  40. data/lib/kwala/templates/code_duplication_summary.html +9 -0
  41. data/lib/kwala/templates/code_formatting_detailed.html +27 -0
  42. data/lib/kwala/templates/code_formatting_summary.html +11 -0
  43. data/lib/kwala/templates/cycle_detection_detailed.html +20 -0
  44. data/lib/kwala/templates/cycle_detection_summary.html +7 -0
  45. data/lib/kwala/templates/cyclomatic_complexity_summary.html +27 -0
  46. data/lib/kwala/templates/executable_files_check_detailed.html +31 -0
  47. data/lib/kwala/templates/executable_files_check_summary.html +20 -0
  48. data/lib/kwala/templates/flagged_comments_detailed.html +22 -0
  49. data/lib/kwala/templates/flagged_comments_summary.html +10 -0
  50. data/lib/kwala/templates/loc_count_detailed.html +24 -0
  51. data/lib/kwala/templates/loc_count_summary.html +14 -0
  52. data/lib/kwala/templates/mdd/1.png +0 -0
  53. data/lib/kwala/templates/mdd/2.png +0 -0
  54. data/lib/kwala/templates/mdd/3.png +0 -0
  55. data/lib/kwala/templates/mdd/4.png +0 -0
  56. data/lib/kwala/templates/mdd/5.png +0 -0
  57. data/lib/kwala/templates/outside_links_summary.html +4 -0
  58. data/lib/kwala/templates/strange_requires_detailed.html +23 -0
  59. data/lib/kwala/templates/strange_requires_summary.html +13 -0
  60. data/lib/kwala/templates/style.css +95 -0
  61. data/lib/kwala/templates/syntax_check_detailed.html +21 -0
  62. data/lib/kwala/templates/syntax_check_summary.html +7 -0
  63. data/lib/kwala/templates/unit_test_detailed.html +66 -0
  64. data/lib/kwala/templates/unit_test_summary.html +70 -0
  65. data/test/tc_build_action.rb +32 -0
  66. data/test/tc_templates.rb +24 -0
  67. metadata +118 -0
@@ -0,0 +1,128 @@
1
+ # $Id: flagged_comments.rb 32 2008-04-02 07:50:18Z zev $
2
+ #
3
+ # This file implements the logic to scan for special comments in
4
+ # a source base.
5
+
6
+ # Copyright (c) 2006, Ubiquitous Business Technology (http://ubit.com)
7
+ # All rights reserved.
8
+ #
9
+ # Redistribution and use in source and binary forms, with or without
10
+ # modification, are permitted provided that the following conditions are
11
+ # met:
12
+ #
13
+ #
14
+ # * Redistributions of source code must retain the above copyright
15
+ # notice, this list of conditions and the following disclaimer.
16
+ #
17
+ # * Redistributions in binary form must reproduce the above
18
+ # copyright notice, this list of conditions and the following
19
+ # disclaimer in the documentation and/or other materials provided
20
+ # with the distribution.
21
+ #
22
+ # * Neither the name of Ubit nor the names of its
23
+ # contributors may be used to endorse or promote products derived
24
+ # from this software without specific prior written permission.
25
+ #
26
+ #
27
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+ #
39
+ # == Author
40
+ # Zev Blut (zb@ubit.com)
41
+
42
+
43
+ class FlaggedCommentsAction < BuildAction
44
+ COMMENTFLAGS = [ "BUG", "FIXME", "???", "TODO", "XXX" ]
45
+ COMMENTREGEXP = Regexp.new("\#\s*(" +
46
+ COMMENTFLAGS.map { |i| Regexp.escape(i)}.join("|") +
47
+ ")\s*:?(.*)")
48
+
49
+ def initialize
50
+ @comment_count = Hash.new { |h,k| h[k] = Array.new }
51
+ end
52
+
53
+ def build_action(context)
54
+ projbase = context.project_directory.split("/").last
55
+ (context.ruby_files + context.test_files).each do |file|
56
+ fcount = collect_comments_from_file(file)
57
+ fcount.each do |cflag, val|
58
+ fnamemap = val.map do |idx, txt|
59
+ nfile = file.split(context.project_directory).last
60
+ ["#{ projbase }/#{ nfile }\##{ idx }" , txt]
61
+ end
62
+ @comment_count[cflag].concat( fnamemap )
63
+ end
64
+ end
65
+ end
66
+
67
+ def summary_display(context)
68
+ template = TemplateFile.new(self.class.summary_template_file)
69
+
70
+ ares = COMMENTFLAGS.map do |ctype|
71
+ { :type => ctype,
72
+ :count => @comment_count[ctype].size
73
+ }
74
+ end
75
+
76
+ context.amrita_data[:com_results] = { :entry => ares }
77
+ loc_base = "#{context.project_name}_com.html"
78
+ context.amrita_data[:com_details] =
79
+ (Amrita::e(:a, :href => loc_base) { "Flagged Comments Details" } )
80
+
81
+ summary_expand(template, context)
82
+ end
83
+
84
+ def detailed_display(context)
85
+ template = TemplateFile.new(self.class.detailed_template_file)
86
+
87
+
88
+ ares = COMMENTFLAGS.map do |ctype|
89
+ { :type => ctype,
90
+ :count => @comment_count[ctype].size,
91
+ :entries => @comment_count[ctype].map do |file, txt|
92
+ {
93
+ :file => Amrita::e(:a, :href => link_to_file(file)) { file },
94
+ :txt => txt
95
+ }
96
+ end
97
+ }
98
+ end
99
+
100
+ context.amrita_data[:com_details] = { :entry => ares }
101
+ det_res = ProjectBuilderUtils.expand_template(template, context.amrita_data)
102
+ det_file = "#{context.output_directory}/#{context.project_name}_com.html"
103
+ [det_file, det_res]
104
+ end
105
+
106
+
107
+ def collect_comments_from_file(file)
108
+ res = Hash.new { |h,k| h[k] = Array.new }
109
+ IO.readlines(file).each_with_index do |line, idx|
110
+ if m = COMMENTREGEXP.match(line)
111
+ res[m[1]]<< [idx + 1 , m[2]]
112
+ end
113
+ end
114
+ res
115
+ end
116
+
117
+ #annotate does the line numbering and pointing
118
+ def link_to_file(file)
119
+ file, line = file.split("#")
120
+ view_url = annotate_url +
121
+ file.to_s + "?annotate=HEAD\#" + line.to_s
122
+ end
123
+
124
+ def annotate_url
125
+ "http://localhost/cgi-bin/viewcvs/cgi/viewcvs.cgi/"
126
+ end
127
+
128
+ end
@@ -0,0 +1,31 @@
1
+ # This is a base action that all external plugins (i.e. gems)
2
+ # should subclass
3
+
4
+ # How would I test this?
5
+ class GemPluginAction < BuildAction
6
+
7
+
8
+ # For now I assume that the gem's templates are in the same directory as the action file
9
+ def self.summary_template_file
10
+ "#{File.dirname(__FILE__)}/#{command_line_action_name}_summary.html"
11
+ end
12
+
13
+ def self.detailed_template_file
14
+ "#{File.dirname(__FILE__)}/#{command_line_action_name}_detailed.html"
15
+ end
16
+
17
+ def self.load_external_gems
18
+ require 'rubygems'
19
+ # Here we do stuff with the gem api to find all external gems that require kwala.
20
+ # We will assume that they are actions and require them
21
+ # Thanks to Chad Fowler for this bit of code
22
+ Gem.cache.search(//).select do |specification|
23
+ specification.dependencies.map{ |dep| dep.name }.include('kwala')
24
+ end.each do |depname|
25
+ require depname.name
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ GemPluginAction.load_external_gems
@@ -0,0 +1,153 @@
1
+ # $Id: loc_count.rb 29 2008-04-02 07:32:44Z zev $
2
+ #
3
+ # This file implements the logic to count the lines of code in
4
+ # a source base.
5
+
6
+ # Copyright (c) 2006, Ubiquitous Business Technology (http://ubit.com)
7
+ # All rights reserved.
8
+ #
9
+ # Redistribution and use in source and binary forms, with or without
10
+ # modification, are permitted provided that the following conditions are
11
+ # met:
12
+ #
13
+ #
14
+ # * Redistributions of source code must retain the above copyright
15
+ # notice, this list of conditions and the following disclaimer.
16
+ #
17
+ # * Redistributions in binary form must reproduce the above
18
+ # copyright notice, this list of conditions and the following
19
+ # disclaimer in the documentation and/or other materials provided
20
+ # with the distribution.
21
+ #
22
+ # * Neither the name of Ubit nor the names of its
23
+ # contributors may be used to endorse or promote products derived
24
+ # from this software without specific prior written permission.
25
+ #
26
+ #
27
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+ #
39
+ # == Author
40
+ # Zev Blut (zb@ubit.com)
41
+
42
+ module LOCCountModule
43
+ def count_loc(file)
44
+ code = comments = blank = 0
45
+ inside_embedded_doc = false
46
+
47
+ IO.readlines(file).each do |line|
48
+ if line =~ /\s*#/
49
+ #ignore comments
50
+ comments += 1
51
+ elsif line =~ /^=begin/
52
+ inside_embedded_doc = true
53
+ comments += 1
54
+ elsif line =~ /^=end/
55
+ inside_embedded_doc = false
56
+ comments += 1
57
+ elsif inside_embedded_doc
58
+ comments += 1
59
+ elsif line =~ /^\s*$/
60
+ #blank space to ignore
61
+ blank += 1
62
+ else
63
+ code+= 1
64
+ end
65
+ end
66
+
67
+ [code, comments, blank]
68
+ end
69
+ end
70
+
71
+
72
+ class LocCountAction < BuildAction
73
+ include LOCCountModule
74
+
75
+ TOTAL = "TOTAL_LOC"
76
+ PROD_CODE = "TOTAL_PRODUCTION_LOC"
77
+ TEST_CODE = "TOTAL_TEST_LOC"
78
+
79
+ def initialize
80
+ @file_loc = Hash.new { |h, k| h[k] = Array.new }
81
+ end
82
+
83
+ def build_action(context)
84
+
85
+ (context.ruby_files + context.test_files).each do |file|
86
+ @file_loc[file] = count_loc(file)
87
+ end
88
+
89
+ @file_loc[TOTAL] = sum_count(@file_loc.keys)
90
+ @file_loc[PROD_CODE] = sum_count(context.ruby_files)
91
+ @file_loc[TEST_CODE] = sum_count(context.test_files)
92
+ end
93
+
94
+ def summary_display(context)
95
+ template = TemplateFile.new(self.class.summary_template_file)
96
+
97
+ ares = [ ["Total", @file_loc[TOTAL]],
98
+ ["Production Code", @file_loc[PROD_CODE]],
99
+ ["Test Code", @file_loc[TEST_CODE]] ].map do |ctype, cdata|
100
+ code, comments, blank, files = *cdata
101
+ ttl = code + comments + blank
102
+ { :type => ctype, :total => ttl,
103
+ :code => code, :code_per => percent(code, ttl),
104
+ :comments => comments, :comments_per => percent(comments, ttl),
105
+ :blank => blank, :blank_per => percent(blank, ttl) ,
106
+ :files => files
107
+ }
108
+ end
109
+
110
+ context.amrita_data[:loc_results] = { :entry => ares }
111
+ loc_base = "#{context.project_name}_loc.html"
112
+ context.amrita_data[:loc_details] =
113
+ (Amrita::e(:a, :href => loc_base) { "Lines of Code Details" } )
114
+
115
+ summary_expand(template, context)
116
+ end
117
+
118
+ def detailed_display(context)
119
+ template = TemplateFile.new(self.class.detailed_template_file)
120
+
121
+ ares = (@file_loc.keys - [TOTAL, PROD_CODE, TEST_CODE]).sort.map do |file|
122
+ code, comments, blank = *(@file_loc[file])
123
+ ttl = code + comments + blank
124
+ { :file => file, :total => ttl,
125
+ :code => code, :code_per => percent(code, ttl),
126
+ :comments => comments, :comments_per => percent(comments, ttl),
127
+ :blank => blank, :blank_per => percent(blank, ttl) }
128
+ end
129
+
130
+ context.amrita_data[:loc_details] = { :entry => ares }
131
+ det_res = ProjectBuilderUtils.expand_template(template, context.amrita_data)
132
+ det_file = "#{context.output_directory}/#{context.project_name}_loc.html"
133
+ [det_file, det_res]
134
+ end
135
+
136
+ def percent(val, total)
137
+ sprintf("%.2f%", (val.to_f / total) * 100)
138
+ end
139
+
140
+ def sum_count(files)
141
+ code = comments = blank = 0
142
+
143
+ files.each do |file|
144
+ fcode, fcomments, fblank = *( @file_loc[file] )
145
+ code += fcode
146
+ comments += fcomments
147
+ blank += fblank
148
+ end
149
+
150
+ [code, comments, blank, files.size]
151
+ end
152
+
153
+ end
@@ -0,0 +1,62 @@
1
+ require "#{File.dirname(__FILE__)}/unit_test"
2
+
3
+ # requires multiruby, part of ZenTest: http://www.zenspider.com/ZSS/Products/ZenTest/
4
+ class MultiRubyUnitTestBuildAction < UnitTestBuildAction
5
+
6
+ MULTIRUBY = '/usr/local/bin/multiruby'
7
+ SITE_RUBY = '/usr/local/lib/ruby/site_ruby/1.8'
8
+
9
+ def self.summary_template_file
10
+ superclass.summary_template_file
11
+ end
12
+
13
+ def self.detailed_template_file
14
+ superclass.detailed_template_file
15
+ end
16
+
17
+ #################
18
+ # Protected
19
+
20
+ def ruby_version
21
+ return @ruby_version if defined? @ruby_version
22
+ version = `#{MULTIRUBY} -v`
23
+ @ruby_version = version.scan(/VERSION = ([\.0-9]*)/).join(', ')
24
+ end
25
+
26
+ def ruby_command_line(pre_requires, file)
27
+ req_cmd = "-I#{SITE_RUBY} -I#{SITE_RUBY}/i686-linux/"
28
+ if pre_requires
29
+ req_cmd << " -r #{pre_requires}"
30
+ end
31
+ "#{MULTIRUBY} #{req_cmd} #{file}"
32
+ end
33
+
34
+ def parse_test_results(data, file)
35
+ version_reg = /([0-9\.]*)#{RES_REGEXP}/im
36
+ version_array = data.split('VERSION = ').map{|s| s.match(version_reg)}.compact
37
+ if version_array.empty?
38
+ [no_match_result(data, file)]
39
+ else
40
+ version_array.map do |m|
41
+ {
42
+ :file_name => file,
43
+ :version_name => m[1],
44
+ :time => m[3],
45
+ :tests => m[5],
46
+ :assertions => m[6],
47
+ :failures => template_error_num(m[7]),
48
+ :errors => template_error_num(m[8]),
49
+ :test_results => parse_out_test_info(m[4]).map {|i| {:test_info => i}}
50
+ }
51
+ end
52
+ end
53
+ end
54
+
55
+ alias :old_time_out_readlines :time_out_readlines
56
+
57
+ def time_out_readlines(io)
58
+ # We give it a minute and a half now
59
+ old_time_out_readlines(io, 90)
60
+ end
61
+
62
+ end
@@ -0,0 +1,85 @@
1
+ # $Id: outside_links.rb 34 2008-04-03 06:01:19Z zev $
2
+ #
3
+ # This file implements an action that creates links to reports
4
+ # not generated by the project builder
5
+
6
+ # Copyright (c) 2006, Ubiquitous Business Technology (http://ubit.com)
7
+ # All rights reserved.
8
+ #
9
+ # Redistribution and use in source and binary forms, with or without
10
+ # modification, are permitted provided that the following conditions are
11
+ # met:
12
+ #
13
+ #
14
+ # * Redistributions of source code must retain the above copyright
15
+ # notice, this list of conditions and the following disclaimer.
16
+ #
17
+ # * Redistributions in binary form must reproduce the above
18
+ # copyright notice, this list of conditions and the following
19
+ # disclaimer in the documentation and/or other materials provided
20
+ # with the distribution.
21
+ #
22
+ # * Neither the name of Ubit nor the names of its
23
+ # contributors may be used to endorse or promote products derived
24
+ # from this software without specific prior written permission.
25
+ #
26
+ #
27
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+ #
39
+ # == Author
40
+ # Zev Blut (zb@ubit.com)
41
+
42
+ class OutsideLinksAction < BuildAction
43
+ BASE_URL = ""
44
+
45
+ def initialize
46
+ no_http = Proc.new do |link, project_name|
47
+ "#{BASE_URL}/#{link}/#{project_name}/"
48
+ end
49
+ http = Proc.new do |link, project_name|
50
+ "#{link}/#{project_name}/"
51
+ end
52
+
53
+ @links = [
54
+ ["rdocs", "Documentation", no_http],
55
+ ["statcvs_output", "StatCVS", no_http],
56
+ ["http://localhost/viewvc", "ViewVC", http],
57
+ ["http://localhost/pragprog/data/rss", "CVS Commit RSS",
58
+ Proc.new { |link, project_name| "#{link}/#{project_name}.rss" }
59
+ ]
60
+ ]
61
+ end
62
+
63
+ def build_action(context)
64
+ #Do nothing
65
+ end
66
+
67
+ def summary_display(context)
68
+ template = TemplateFile.new(self.class.summary_template_file)
69
+ context.amrita_data[:outside_links] = @links.map do |link, lname, action|
70
+ {
71
+ :item => Amrita::e(:h3) do
72
+ url = action.call(link, context.project_name)
73
+ Amrita::e(:a, :href => url) { lname }
74
+ end
75
+ }
76
+ end
77
+
78
+ summary_expand(template, context)
79
+ end
80
+
81
+ def self.detailed_template_file
82
+ nil
83
+ end
84
+
85
+ end