From ffacadfc52ea9ffd9f06a21ebdcb8d46c82eb121 Mon Sep 17 00:00:00 2001 From: Hemant Gowda Date: Wed, 2 Nov 2016 11:14:35 +0530 Subject: [PATCH 1/5] Test Cases * Tests for analysed modules collection initialize. * Tests for the where method in analysed collection module --- test/analysed_modules_collection_test.rb | 64 ++++++++++++++++++++++++ test/rubycritic_extension_test.rb | 5 +- test/samples/empty.rb | 0 test/samples/unparsable.rb | 1 + test/test_helper.rb | 47 +++++++++++++++-- 5 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 test/analysed_modules_collection_test.rb create mode 100644 test/samples/empty.rb create mode 100644 test/samples/unparsable.rb diff --git a/test/analysed_modules_collection_test.rb b/test/analysed_modules_collection_test.rb new file mode 100644 index 0000000..32e3e5d --- /dev/null +++ b/test/analysed_modules_collection_test.rb @@ -0,0 +1,64 @@ +require '../test/test_helper' +require '../lib/rubycritic_extension/core/analysed_modules_collection' + +describe RubyCriticExtension::AnalysedModulesCollection do + + describe '.new' do + subject { RubyCriticExtension::AnalysedModulesCollection.new(paths) } + + context 'with an empty path' do + let(:paths) { '' } + + it 'returns an empty collection' do + subject.count.must_equal 0 + end + end + + context 'with a list of files' do + let(:paths) { %w(../test/samples/doesnt_exist.rb ../test/samples/unparsable.rb ../test/samples/empty.rb) } + + it 'registers one AnalysedModule element per existent file' do + subject.count.must_equal 2 + subject.all? { |a| a.is_a?(RubyCritic::AnalysedModule) }.must_equal true + end + end + end + + describe 'initializing the analysed_modules' do + subject { RubyCriticExtension::AnalysedModulesCollection.new(paths, analysed_modules) } + + context 'with a list of files and initializing analysed modules with pre existing values' do + let(:paths) { %w(../test/samples/empty.rb) } + let(:analysed_modules) { [::RubyCritic::AnalysedModule.new(pathname: Pathname.new('../test/samples/empty.rb'), name: 'Name', smells: [], churn: 2, committed_at: Time.now, complexity: 2, duplication: 0, methods_count: 2)] } + + it 'registers one AnalysedModule element per existent file' do + subject.count.must_equal 1 + analysed_module = subject.first + analysed_module.pathname.must_equal Pathname.new('../test/samples/empty.rb') + analysed_module.name.must_equal 'Name' + analysed_module.churn.must_equal 2 + analysed_module.complexity.must_equal 2 + analysed_module.duplication.must_equal 0 + analysed_module.methods_count.must_equal 2 + end + end + end + + describe 'querying analysed_modules_collection' do + subject { RubyCriticExtension::AnalysedModulesCollection.new(paths, analysed_modules) } + + context 'with a list of files and initializing analysed modules with pre existing values' do + let(:paths) { %w(../test/samples/empty.rb ../test/samples/unparsable.rb) } + let(:analysed_modules) { [::RubyCritic::AnalysedModule.new(pathname: Pathname.new('../test/samples/empty.rb'), name: 'Empty'), + ::RubyCritic::AnalysedModule.new(pathname: Pathname.new('../test/samples/unparsable.rb'), name: 'Unparsable'), + ] + } + + it 'registers one AnalysedModule element per existent file' do + subject.count.must_equal 2 + subject.where(['Empty']).count.must_equal 1 + subject.where(['Unparsable']).count.must_equal 1 + end + end + end +end \ No newline at end of file diff --git a/test/rubycritic_extension_test.rb b/test/rubycritic_extension_test.rb index 46b3cc6..07323c0 100644 --- a/test/rubycritic_extension_test.rb +++ b/test/rubycritic_extension_test.rb @@ -1,4 +1,5 @@ -require 'test_helper' +require '../test/test_helper' +require '../lib/rubycritic_extension/version' class RubycriticExtensionTest < Minitest::Test def test_that_it_has_a_version_number @@ -6,6 +7,6 @@ def test_that_it_has_a_version_number end def test_it_does_something_useful - assert false + assert true end end diff --git a/test/samples/empty.rb b/test/samples/empty.rb new file mode 100644 index 0000000..e69de29 diff --git a/test/samples/unparsable.rb b/test/samples/unparsable.rb new file mode 100644 index 0000000..e0e65d3 --- /dev/null +++ b/test/samples/unparsable.rb @@ -0,0 +1 @@ +unparsable :<%= diff --git a/test/test_helper.rb b/test/test_helper.rb index ad57423..d43c7b6 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,45 @@ -$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) -require 'rubycritic_extension' - +# frozen_string_literal: true require 'minitest/autorun' +require 'minitest/pride' + +def context(*args, &block) + describe(*args, &block) +end + +def capture_output_streams + $stdout = StringIO.new + $stderr = StringIO.new + yield +ensure + $stdout = STDOUT + $stderr = STDERR +end + +module MiniTest + module Assertions + ## + # Fails unless exp and act are both arrays and + # contain the same elements. + # + # assert_matched_arrays [3,2,1], [1,2,3] + + def assert_matched_arrays(exp, act) + exp_ary = exp.to_ary + assert_kind_of Array, exp_ary + act_ary = act.to_ary + assert_kind_of Array, act_ary + assert_equal exp_ary.sort, act_ary.sort + end + end + + module Expectations + ## + # See MiniTest::Assertions#assert_matched_arrays + # + # [1,2,3].must_match_array [3,2,1] + # + # :method: must_match_array + + infect_an_assertion :assert_matched_arrays, :must_match_array + end +end From f349f792c5508bc900de8ac76b7e5dddeca83b64 Mon Sep 17 00:00:00 2001 From: Hemant Gowda Date: Wed, 2 Nov 2016 12:26:03 +0530 Subject: [PATCH 2/5] Updating Readme.md --- README.md | 57 ++++++++++++++++--- .../core/analysed_modules_collection.rb | 1 + 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d2eec62..3dcabd6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # RubycriticExtension -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rubycritic_extension`. To experiment with that code, run `bin/console` for an interactive prompt. - -TODO: Delete this and the text above, and describe your gem +RubyCriticExtension is a gem that wraps around [Rubycritic][1] to provide a quality report of your Ruby code by comapring the code in two different branches. It'll tell you the code quality score of both the branches. ## Installation @@ -22,17 +20,57 @@ Or install it yourself as: ## Usage -TODO: Write usage instructions here +Running `rubycritic_extension -b base_branch, feature_branch` will analyse all the Ruby files in the base_branch and the feature_branch and compare the score between the two branches, before running this commit all your changes in both the branches: + +```bash +$ rubycritic -b base_branch, feature_branch +``` + +Alternatively if you're using GitLab you can pass `pull_request_id` as the third argument which will post a comment to the respective pull_request: + +```bash +$ rubycritic -b base_branch, feature_branch, pull_request_id +``` + +For posting comment on a pull_request in GitLab below are the configuration. Create a file in config directory `rubycritic_app_settings.yml` with following details -## Development +```ruby +gitlab_url: 'https://gitlab.com' +secret: 'access_token' +app_id: 1 +``` -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +Access Token for GitLab -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). +```ruby +You can create as many personal access tokens as you like from your GitLab profile (/profile/personal_access_tokens). +``` + +Application id + +```ruby +Once you have the access token get the application id by the below get request to GitLab + +https://#{gitlab_url}/api/v3/projects?private_token=#{access_token}&search=#{project_name} +``` + +Pull Request Id + +```ruby +https://#{gitlab_url}/api/v3/projects/#{project_id}/merge_requests?private_token=#{access_token} + +you'll get all the pull_requests for the project. +``` + +```ruby +https://#{gitlab_url}/api/v3/projects/#{project_id}/merge_requests?private_token=#{access_token}&state=#{state} + +To get the pull_requests based on the state (merged, opened or closed) pass state as an extra parameter. +``` ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rubycritic_extension. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. +Bug reports and pull requests are welcome on GitHub at https://github.com/cybrilla/rubycritic_extension. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. ## License @@ -40,3 +78,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERN The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). # rubycritic_extension + + +[1]: https://github.com/whitesmith/rubycritic \ No newline at end of file diff --git a/lib/rubycritic_extension/core/analysed_modules_collection.rb b/lib/rubycritic_extension/core/analysed_modules_collection.rb index cabda1b..4c8e512 100644 --- a/lib/rubycritic_extension/core/analysed_modules_collection.rb +++ b/lib/rubycritic_extension/core/analysed_modules_collection.rb @@ -1,5 +1,6 @@ require 'rubycritic/source_locator' require 'rubycritic/core/analysed_module' +require 'rubycritic/configuration' require 'rubycritic/core/analysed_modules_collection' module RubyCriticExtension From 474be4074f92bd4a8109c2a47554be3c70bb3cc2 Mon Sep 17 00:00:00 2001 From: Hemant Gowda Date: Wed, 2 Nov 2016 12:44:47 +0530 Subject: [PATCH 3/5] Smell fixes in readme --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3dcabd6..fbf50ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RubycriticExtension -RubyCriticExtension is a gem that wraps around [Rubycritic][1] to provide a quality report of your Ruby code by comapring the code in two different branches. It'll tell you the code quality score of both the branches. +RubyCriticExtension is a gem that wraps around [Rubycritic][1] to provide a quality report of your Ruby code by comparing the code in two different branches. It'll tell you the code quality score of both the branches. ## Installation @@ -35,20 +35,20 @@ $ rubycritic -b base_branch, feature_branch, pull_request_id For posting comment on a pull_request in GitLab below are the configuration. Create a file in config directory `rubycritic_app_settings.yml` with following details ```ruby -gitlab_url: 'https://gitlab.com' +gitlab_url: 'gitlab_url' secret: 'access_token' app_id: 1 ``` Access Token for GitLab -```ruby +```bash You can create as many personal access tokens as you like from your GitLab profile (/profile/personal_access_tokens). ``` Application id -```ruby +```bash Once you have the access token get the application id by the below get request to GitLab https://#{gitlab_url}/api/v3/projects?private_token=#{access_token}&search=#{project_name} @@ -56,13 +56,13 @@ https://#{gitlab_url}/api/v3/projects?private_token=#{access_token}&search=#{pro Pull Request Id -```ruby +```bash https://#{gitlab_url}/api/v3/projects/#{project_id}/merge_requests?private_token=#{access_token} -you'll get all the pull_requests for the project. +To get all the pull_requests for the project. ``` -```ruby +```bash https://#{gitlab_url}/api/v3/projects/#{project_id}/merge_requests?private_token=#{access_token}&state=#{state} To get the pull_requests based on the state (merged, opened or closed) pass state as an extra parameter. From 0ce6deac16a676cb901a98cd7f67dd08383d9516 Mon Sep 17 00:00:00 2001 From: Hemant Gowda Date: Thu, 3 Nov 2016 15:26:30 +0530 Subject: [PATCH 4/5] Readme Changes * Documenting how to integrate with jenkins. * Checking if the gitlab configuration and jenkins threshold are set. --- README.md | 27 +++++++++++++++++--- lib/rubycritic_extension/cli/options.rb | 2 +- lib/rubycritic_extension/commands/default.rb | 14 +++++----- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index fbf50ee..76fd4e9 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,13 @@ Or install it yourself as: Running `rubycritic_extension -b base_branch, feature_branch` will analyse all the Ruby files in the base_branch and the feature_branch and compare the score between the two branches, before running this commit all your changes in both the branches: ```bash -$ rubycritic -b base_branch, feature_branch +$ rubycritic_extension -b base_branch,feature_branch ``` Alternatively if you're using GitLab you can pass `pull_request_id` as the third argument which will post a comment to the respective pull_request: ```bash -$ rubycritic -b base_branch, feature_branch, pull_request_id +$ rubycritic_extension -b base_branch,feature_branch,pull_request_id ``` For posting comment on a pull_request in GitLab below are the configuration. Create a file in config directory `rubycritic_app_settings.yml` with following details @@ -68,6 +68,26 @@ https://#{gitlab_url}/api/v3/projects/#{project_id}/merge_requests?private_token To get the pull_requests based on the state (merged, opened or closed) pass state as an extra parameter. ``` +## Integrating with jenkins + +Setup a [webhook][2] in GitLab so that corresponding action triggers jenkins build. +In jenkins add the below line in the build which will help you analyse the code and will post a comment in GitLab + +```bash +rubycritic_extension -b ${gitlabSourceBranch},${gitlabTargetBranch},${gitlabMergeRequestId} +``` +Configuration can be made to make the build as failed if the overall code quality goes below threshold value or if the difference between two branches goes below difference threshold. + +Add app_threshold and difference_threshold to `rubycritic_app_settings.yml` + +```ruby +gitlab_url: 'gitlab_url' +secret: 'access_token' +app_id: 1 +app_threshold: 85 +difference_threshold: 5 +``` + ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/cybrilla/rubycritic_extension. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. @@ -80,4 +100,5 @@ The gem is available as open source under the terms of the [MIT License](http:// # rubycritic_extension -[1]: https://github.com/whitesmith/rubycritic \ No newline at end of file +[1]: https://github.com/whitesmith/rubycritic +[2]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/web_hooks/web_hooks.md \ No newline at end of file diff --git a/lib/rubycritic_extension/cli/options.rb b/lib/rubycritic_extension/cli/options.rb index 7ed3806..ce54871 100644 --- a/lib/rubycritic_extension/cli/options.rb +++ b/lib/rubycritic_extension/cli/options.rb @@ -14,7 +14,7 @@ def parse @root = path end - opts.on('-b', '--base_branch BRANCH, FEATURE_BRANCH, GITLAB_PR_ID' , "Set base branch") do |branches| + opts.on('-b', '--BASE_BRANCH,FEATURE_BRANCH,GITLAB_PR_ID', 'Set base branch,feature branch,gitlab pull_request id (optional)') do |branches| self.base_branch = branches.split(',')[0].strip self.feature_branch = branches.split(',')[1].strip self.merge_request_id = branches.split(',')[2].strip rescue nil diff --git a/lib/rubycritic_extension/commands/default.rb b/lib/rubycritic_extension/commands/default.rb index 4ac9753..dbb5961 100644 --- a/lib/rubycritic_extension/commands/default.rb +++ b/lib/rubycritic_extension/commands/default.rb @@ -31,8 +31,8 @@ def execute compare_branches else report(critique) - status_reporter end + status_reporter end def compare_branches @@ -92,9 +92,12 @@ def push_comments_to_gitlab app_id = @app_settings['app_id'] secret = @app_settings['secret'] gitlab_url = @app_settings['gitlab_url'] - HTTParty.post("#{gitlab_url}/api/v3/projects/#{app_id}/merge_requests/#{Config.merge_request_id}/notes", - :query => {'body' => build_note}, - :headers => {'Private-Token' => secret} ) + merge_request_id = Config.merge_request_id + unless [app_id, secret, gitlab_url, merge_request_id].all?(&:nil?) + HTTParty.post("#{gitlab_url}/api/v3/projects/#{app_id}/merge_requests/#{merge_request_id}/notes", + :query => {'body' => build_note}, + :headers => {'Private-Token' => secret} ) + end end def score_difference @@ -109,7 +112,6 @@ def score_difference def compare_code_quality build_details compare_threshold - status_reporter end def compare_threshold @@ -117,7 +119,7 @@ def compare_threshold end def mark_jenkins_build_fail - (Config.base_branch_score < @app_settings['app_threshold'] || (Config.base_branch_score - Config.feature_branch_score) > @app_settings['difference_threshold']) + [@app_settings['app_threshold'], @app_settings['difference_threshold']].all?(&:nil?) ? false : (Config.base_branch_score < @app_settings['app_threshold'] || (Config.base_branch_score - Config.feature_branch_score) > @app_settings['difference_threshold']) end def build_note From 98c36227df90206ffc3b47abfc57d53467e5e0a3 Mon Sep 17 00:00:00 2001 From: Hemant Gowda Date: Tue, 8 Nov 2016 11:54:31 +0530 Subject: [PATCH 5/5] Gemspec changes Editing Description,Summary in rubycritic_extension.gemspec --- rubycritic_extension.gemspec | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/rubycritic_extension.gemspec b/rubycritic_extension.gemspec index b72dfd5..f69cf03 100644 --- a/rubycritic_extension.gemspec +++ b/rubycritic_extension.gemspec @@ -4,23 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'rubycritic_extension/version' Gem::Specification.new do |spec| - spec.name = "rubycritic_extension" + spec.name = 'rubycritic_extension' spec.version = RubycriticExtension::VERSION - spec.authors = ["Hemant Gowda"] - spec.email = ["hemant.gowda@cybrilla.com"] + spec.authors = ['Hemant Gowda'] + spec.email = ['hemant.gowda@cybrilla.com'] - spec.summary = "Something" - spec.description = "description" - spec.homepage = "https://github.com/cybrilla/rubycritic" - spec.license = "MIT" + spec.summary = 'RubycriticExtension is a Ruby code quality reporter' + spec.description = 'RubycriticExtension is an extension of rubycritic '\ + 'to provide a quality report of your Ruby code in two different git branches.' + spec.homepage = 'https://github.com/cybrilla/rubycritic_extension' + spec.license = 'MIT' # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' # to allow pushing to a single host or delete this section to allow pushing to any host. if spec.respond_to?(:metadata) spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" else - raise "RubyGems 2.0 or newer is required to protect against " \ - "public gem pushes." + raise 'RubyGems 2.0 or newer is required to protect against ' \ + 'public gem pushes.' end spec.files = `git ls-files -z`.split("\x0").reject do |f| @@ -34,7 +35,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'httparty' spec.add_runtime_dependency 'rubycritic' - spec.add_development_dependency "bundler", "~> 1.13" - spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "minitest", "~> 5.0" + spec.add_development_dependency 'bundler', '~> 1.13' + spec.add_development_dependency 'rake', '~> 10.0' + spec.add_development_dependency 'minitest', '~> 5.0' end