kolekti_metricfu 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING.lesser ADDED
@@ -0,0 +1,165 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kolekti_metricfu.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # KolektiMetricfu
2
+
3
+ [![Code Climate](https://codeclimate.com/github/mezuro/kolekti_metricfu/badges/gpa.svg)](https://codeclimate.com/github/mezuro/kolekti_metricfu) <a href="https://codeclimate.com/github/mezuro/kolekti_metricfu/coverage"><img src="https://codeclimate.com/github/mezuro/kolekti_metricfu/badges/coverage.svg" /></a>
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'kolekti_metricfu'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install kolekti_metricfu
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Development
26
+
27
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
28
+
29
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
30
+
31
+ ## Contributing
32
+
33
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/kolekti_metricfu.
34
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RuboCop::RakeTask.new
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ # Copied from https://github.com/cucumber/cucumber-ruby/blob/master/Rakefile#L6
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
11
+ Dir['gem_tasks/**/*.rake'].each { |rake| load rake }
12
+
13
+ task default: [:spec, :cucumber, :rubocop]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kolekti/metricfu"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ # Copied from https://github.com/cucumber/cucumber-ruby/blob/master/gem_tasks/cucumber.rake
2
+
3
+ require 'cucumber/rake/task'
4
+ require 'cucumber/platform'
5
+
6
+ Cucumber::Rake::Task.new(:features) do |t|
7
+ t.fork = true
8
+ end
9
+
10
+ task cucumber: :features
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kolekti/metricfu/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'kolekti_metricfu'
8
+ spec.version = Kolekti::Metricfu::VERSION
9
+ spec.authors = ['Daniel Miranda',
10
+ "Diego Araújo",
11
+ "Eduardo Araújo",
12
+ 'Rafael Reggiani Manzo']
13
+ spec.email = ['danielkza2@gmail.com',
14
+ 'diegoamc90@gmail.com',
15
+ 'duduktamg@hotmail.com',
16
+ 'rr.manzo@protonmail.com']
17
+ spec.summary = 'Metric collecting support for Ruby that servers Kolekti.'
18
+ spec.homepage = 'https://github.com/mezuro/kolekti_metricfu'
19
+
20
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_dependency 'kolekti', '~> 1.1'
26
+ spec.add_dependency 'metric_fu', '~> 4.12.0'
27
+ spec.add_dependency 'flog', '~> 4.3.2' # Restriction necessary until https://github.com/metricfu/metric_fu/pull/274 does not get merged, released and we update our metric_fu requirements
28
+ # Version 0.2.5 requires ruby >= 2.1 while CentOS 7 is still running 2.0.0
29
+ spec.add_dependency 'unparser', '< 0.2.5' if RUBY_VERSION < '2.1.0'
30
+
31
+ spec.add_development_dependency 'bundler', '~> 1.11'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'simplecov'
35
+ spec.add_development_dependency 'codeclimate-test-reporter'
36
+ spec.add_development_dependency 'cucumber', '~> 2.1'
37
+ spec.add_development_dependency 'factory_girl', '~> 4.5'
38
+ spec.add_development_dependency 'byebug'
39
+ spec.add_development_dependency 'rubocop', '>= 0.36'
40
+ end
@@ -0,0 +1,57 @@
1
+ require 'tempfile'
2
+
3
+ module Kolekti
4
+ module Metricfu
5
+ class Collector < Kolekti::Collector
6
+ def self.available?
7
+ # FIXME: below is the better form of writing this, but it does not look compatible with ruby 2.1.5 and 2.0.0
8
+ # system('metric_fu --version', [:out, :err] => '/dev/null') ? true : false
9
+ system('metric_fu --version', out: '/dev/null', err: '/dev/null') ? true : false
10
+ end
11
+
12
+ def initialize
13
+ supported_metrics = parse_supported_metrics(
14
+ File.expand_path('../metrics.yml', __FILE__),
15
+ 'MetricFu',
16
+ [:RUBY]
17
+ )
18
+
19
+ super('MetricFu', 'Set of Ruby metric tools', supported_metrics)
20
+ end
21
+
22
+ def collect_metrics(code_directory, wanted_metric_configurations, persistence_strategy)
23
+ tmp_file = Tempfile.new(['metric_fu', '.yml'], code_directory)
24
+ begin
25
+ Dir.chdir(code_directory) do
26
+ unless system('metric_fu', '--format', 'yaml', '--out', tmp_file.path, '--no-reek', out: '/dev/null', err: '/dev/null')
27
+ raise Kolekti::CollectorError.new('MetricFu failed')
28
+ end
29
+ end
30
+ Kolekti::Metricfu::Parsers.parse_all(tmp_file.path, wanted_metric_configurations, persistence_strategy)
31
+ ensure
32
+ tmp_file.close!
33
+ end
34
+ end
35
+
36
+ def clean(code_directory, wanted_metric_configurations)
37
+ # Does not need to do anything, as collect metrics cleans things up already through a rescue block
38
+ end
39
+
40
+ def default_value_from(metric_configuration)
41
+ metric = metric_configuration.metric
42
+ if metric.type != 'NativeMetricSnapshot'
43
+ raise Kolekti::UnavailableMetricError.new('Invalid Metric configuration type')
44
+ end
45
+
46
+ parser = nil
47
+ if metric.metric_collector_name == self.name
48
+ parser = Kolekti::Metricfu::Parsers::PARSERS[metric.code.to_sym]
49
+ end
50
+
51
+ raise Kolekti::UnavailableMetricError.new('Metric configuration does not belong to MetricFu') if parser.nil?
52
+
53
+ parser.default_value
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+ :metrics:
2
+ #:abc:
3
+ # :name: ABC complexity
4
+ # :description: The ABC metric measures size/complexity by counting the number of Assignments (A), Branches (B) and Conditions (C) and assigns a single numerical score
5
+ # :scope: METHOD
6
+
7
+ #:churn:
8
+ # :name: Code churn
9
+ # :description: Code churn is how often code is changing over time
10
+ # :scope: CLASS
11
+
12
+ :flog:
13
+ :name: Pain
14
+ :description: Measures how hard (painful) it is to test the code
15
+ :scope: METHOD
16
+ :type: NativeMetricSnapshot
17
+
18
+ :saikuro:
19
+ :name: Cyclomatic Complexity
20
+ :description: Cyclomatic complexity is a graphical measurement of the number of possible paths through the normal flow of a program
21
+ :scope: METHOD
22
+ :type: NativeMetricSnapshot
23
+
24
+ :flay:
25
+ :name: Duplicate Code
26
+ :description: 'Flay analyzes code for structural similarities. Differences in literal values, variable, class, method names, whitespace, programming style, braces vs do/end, etc are all ignored'
27
+ :type: HotspotMetricSnapshot
@@ -0,0 +1,22 @@
1
+ module Kolekti
2
+ module Metricfu
3
+ module Parsers
4
+ class Base < Kolekti::Parser
5
+ def self.module_name_suffix(module_name)
6
+ return '' if module_name.to_s.end_with?('#none')
7
+
8
+ # Replace Saikuro's representation of a class method (#self.method) with Flog's
9
+ # (::method) so we can treat both the same later.
10
+ module_name = module_name.gsub('#self.', '::')
11
+ # Now split up the last component of the module name so it doesn't get it's
12
+ # prefixes (# or ::) replaced with . (our own separator).
13
+ module_path, prefix, module_name = module_name.rpartition(/#|::/)
14
+ # Replace the separators in the path (and only the path) with dots
15
+ module_path.gsub!(/#|::/, '.')
16
+ # Put everything back together
17
+ '.' + module_path + '.' + prefix + module_name
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module Kolekti
2
+ module Metricfu
3
+ module Parsers
4
+ class Flay < Base
5
+ def self.parse(collected_metrics_hash, metric_configuration, persistence_strategy)
6
+ collected_metrics_hash[:matches].each do |match|
7
+ reason = match[:reason]
8
+ results = match[:matches].map do |line_match|
9
+ line_number = line_match[:line].to_i
10
+ module_name = parse_file_name(line_match[:name])
11
+ { 'module_name' => module_name,
12
+ 'line' => line_number,
13
+ 'message' => reason }
14
+ end
15
+
16
+ persistence_strategy.create_related_hotspot_metric_results(metric_configuration, results) unless results.empty?
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ module Kolekti
2
+ module Metricfu
3
+ module Parsers
4
+ class Flog < Base
5
+ def self.parse(collected_metrics_hash, metric_configuration, persistence_strategy)
6
+ collected_metrics_hash[:method_containers].each do |method_container|
7
+ next if method_container[:path].nil? || method_container[:path].empty?
8
+ name_prefix = self.parse_file_name(method_container[:path])
9
+
10
+ method_container[:methods].each do |name, result|
11
+ value = result[:score]
12
+
13
+ name_suffix = module_name_suffix(name)
14
+
15
+ next if name_suffix.nil? || name_suffix.empty?
16
+ module_name = name_prefix + name_suffix
17
+ granularity = KalibroClient::Entities::Miscellaneous::Granularity::METHOD
18
+
19
+ persistence_strategy.create_tree_metric_result(metric_configuration, module_name, value.to_f, granularity)
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.default_value
25
+ 0.0 # No pain, no gain
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ module Kolekti
2
+ module Metricfu
3
+ module Parsers
4
+ class Saikuro < Base
5
+ def self.parse(collected_metrics_hash, metric_configuration, persistence_strategy)
6
+ collected_metrics_hash[:files].each do |file|
7
+ name_prefix = parse_file_name(file[:filename])
8
+ file[:classes].each do |cls|
9
+ # Filter duplicate methods, picking only the latest. Fortunately Hash::[] will pick the latest element
10
+ # when receiveing an array.
11
+ methods_by_name = cls[:methods].map { |method| [method[:name], method] }
12
+ # FIXME: Since ruby 2.1 this can be replaced by 'methods_by_name.to_hash'
13
+ methods = Hash[methods_by_name]
14
+ methods.each_value do |method|
15
+ value = method[:complexity]
16
+ name_suffix = module_name_suffix(method[:name])
17
+ module_name = name_prefix + name_suffix
18
+
19
+ granularity = KalibroClient::Entities::Miscellaneous::Granularity::METHOD
20
+ persistence_strategy.create_tree_metric_result(metric_configuration, module_name, value.to_f, granularity)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.default_value
27
+ 1.0 # Just one branch
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ require 'kolekti/metricfu/parsers/base'
2
+ require 'kolekti/metricfu/parsers/flog'
3
+ require 'kolekti/metricfu/parsers/saikuro'
4
+ require 'kolekti/metricfu/parsers/flay'
5
+
6
+ module Kolekti
7
+ module Metricfu
8
+ module Parsers
9
+ PARSERS = {
10
+ flog: Flog,
11
+ saikuro: Saikuro,
12
+ flay: Flay
13
+ }.freeze
14
+
15
+ def self.parse_all(results_yaml_path, wanted_metric_configurations, persistence_strategy)
16
+ parsed_result = YAML.load_file(results_yaml_path)
17
+
18
+ wanted_metric_configurations.each do |code, metric_configuration|
19
+ code_sym = code.to_sym
20
+ PARSERS[code_sym].parse(parsed_result[code_sym], metric_configuration, persistence_strategy)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ module Kolekti
2
+ module Metricfu
3
+ VERSION = '0.0.4'.freeze
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ require 'kolekti'
2
+
3
+ require 'kolekti/metricfu/version'
4
+ require 'kolekti/metricfu/collector'
5
+ require 'kolekti/metricfu/parsers'
6
+
7
+ module Kolekti
8
+ module Metricfu
9
+ # Your code goes here...
10
+ end
11
+ end