Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 70 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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 comparing the code in two different branches. It'll tell you the code quality score of both the branches.

## Installation

Expand All @@ -22,21 +20,85 @@ 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_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_extension -b base_branch,feature_branch,pull_request_id
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameters should be space separated not comma separated (like unix commands)
eg.

rubycritic-ext -b base_branch feature_branch -p pull_request_id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought -b and -p can be optional, since we can assume the extension does only two things -

  1. runs rubycritic on two branches - hence first 2 args are branch names
  2. optionally posts to PR - hence third arg optional 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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yaml

gitlab_url: 'gitlab_url'
secret: 'access_token'
app_id: 1
```

Access Token for GitLab

```bash
You can create as many personal access tokens as you like from your GitLab profile (/profile/personal_access_tokens).
```

Application id

## Development
```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}
```

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.
Pull Request Id

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).
```bash
https://#{gitlab_url}/api/v3/projects/#{project_id}/merge_requests?private_token=#{access_token}

To get all the pull_requests for the project.
```

```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.
```

## 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/[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

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
[2]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/web_hooks/web_hooks.md
2 changes: 1 addition & 1 deletion lib/rubycritic_extension/cli/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 8 additions & 6 deletions lib/rubycritic_extension/commands/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ def execute
compare_branches
else
report(critique)
status_reporter
end
status_reporter
end

def compare_branches
Expand Down Expand Up @@ -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
Expand All @@ -109,15 +112,14 @@ def score_difference
def compare_code_quality
build_details
compare_threshold
status_reporter
end

def compare_threshold
`exit 1` if mark_jenkins_build_fail
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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'rubycritic/source_locator'
require 'rubycritic/core/analysed_module'
require 'rubycritic/configuration'
require 'rubycritic/core/analysed_modules_collection'

module RubyCriticExtension
Expand Down
25 changes: 13 additions & 12 deletions rubycritic_extension.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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|
Expand All @@ -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
64 changes: 64 additions & 0 deletions test/analysed_modules_collection_test.rb
Original file line number Diff line number Diff line change
@@ -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
5 changes: 3 additions & 2 deletions test/rubycritic_extension_test.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
require 'test_helper'
require '../test/test_helper'
require '../lib/rubycritic_extension/version'

class RubycriticExtensionTest < Minitest::Test
def test_that_it_has_a_version_number
refute_nil ::RubycriticExtension::VERSION
end

def test_it_does_something_useful
assert false
assert true
end
end
Empty file added test/samples/empty.rb
Empty file.
1 change: 1 addition & 0 deletions test/samples/unparsable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
unparsable :<%=
47 changes: 44 additions & 3 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
@@ -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 <tt>exp</tt> and <tt>act</tt> 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