pronto-bigfiles 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +20 -0
  3. data/.gitignore +15 -0
  4. data/.pronto.yml +5 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +74 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +16 -0
  9. data/CODE_OF_CONDUCT.md +76 -0
  10. data/Gemfile +6 -0
  11. data/Gemfile.lock +234 -0
  12. data/LICENSE.txt +21 -0
  13. data/Makefile +16 -0
  14. data/README.md +78 -0
  15. data/Rakefile +0 -0
  16. data/bin/console +15 -0
  17. data/bin/setup +8 -0
  18. data/coverage/.last_run.json +5 -0
  19. data/exe/pronto-bigfiles +4 -0
  20. data/feature/pronto/big_files_cli_spec.rb +88 -0
  21. data/feature/spec_helper.rb +0 -0
  22. data/lib/pronto/bigfiles/message_creator.rb +31 -0
  23. data/lib/pronto/bigfiles/patch_inspector.rb +45 -0
  24. data/lib/pronto/bigfiles/patch_wrapper.rb +28 -0
  25. data/lib/pronto/bigfiles/version.rb +7 -0
  26. data/lib/pronto/bigfiles.rb +35 -0
  27. data/metrics/bigfiles_high_water_mark +1 -0
  28. data/metrics/brakeman_high_water_mark +1 -0
  29. data/metrics/bundle-audit_high_water_mark +1 -0
  30. data/metrics/cane_high_water_mark +1 -0
  31. data/metrics/eslint_high_water_mark +1 -0
  32. data/metrics/flake8_high_water_mark +1 -0
  33. data/metrics/flay_high_water_mark +1 -0
  34. data/metrics/flog_high_water_mark +1 -0
  35. data/metrics/jscs_high_water_mark +1 -0
  36. data/metrics/mdl_high_water_mark +1 -0
  37. data/metrics/punchlist_high_water_mark +1 -0
  38. data/metrics/pycodestyle_high_water_mark +1 -0
  39. data/metrics/rails_best_practices_high_water_mark +1 -0
  40. data/metrics/rubocop_high_water_mark +1 -0
  41. data/metrics/scalastyle_high_water_mark +1 -0
  42. data/metrics/shellcheck_high_water_mark +1 -0
  43. data/pronto-bigfiles.gemspec +49 -0
  44. data/rakelib/ci.rake +4 -0
  45. data/rakelib/clear_metrics.rake +8 -0
  46. data/rakelib/default.rake +3 -0
  47. data/rakelib/feature.rake +9 -0
  48. data/rakelib/gem_tasks.rake +3 -0
  49. data/rakelib/localtest.rake +4 -0
  50. data/rakelib/pronto.rake +15 -0
  51. data/rakelib/quality.rake +23 -0
  52. data/rakelib/spec.rake +9 -0
  53. data/rakelib/update_bundle_audit.rake +6 -0
  54. metadata +243 -0
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pronto/bigfiles'
4
+ require 'tmpdir'
5
+ require 'open3'
6
+
7
+ describe Pronto::BigFiles do
8
+ let(:env) do
9
+ {
10
+ # Avoid spurious deprecation warnings in things which are out of
11
+ # our control
12
+ 'RUBYOPT' => '-W0',
13
+ }
14
+ end
15
+
16
+ describe 'bundle exec pronto list' do
17
+ it 'lists this as a runner' do
18
+ out, exit_code = Open3.capture2e(env, 'bundle exec pronto list')
19
+ expect(out).to include("bigfiles\n")
20
+ expect(exit_code).to eq(0)
21
+ end
22
+ end
23
+
24
+ describe 'bundle exec pronto run --staged -r bigfiles -f text' do
25
+ let(:pronto_command) do
26
+ 'bundle exec pronto run --staged -r bigfiles -f text'
27
+ end
28
+
29
+ let(:results) { Open3.capture2e(env, pronto_command) }
30
+ let(:out) { results[0] }
31
+ let(:exit_code) { results[1] }
32
+
33
+ around do |example|
34
+ Dir.mktmpdir do |dir|
35
+ Dir.chdir(dir) do
36
+ system('git init')
37
+ system('git config user.email "you@example.com"')
38
+ system('git config user.name "Fake User"')
39
+ example_files_committed.each do |filename, contents|
40
+ File.write(filename, contents)
41
+ end
42
+ system('git add .')
43
+ system('git commit -m "First commit"')
44
+ example_files_staged.each do |filename, contents|
45
+ File.write(filename, contents)
46
+ end
47
+ system('git add .')
48
+ example.run
49
+ end
50
+ end
51
+ end
52
+
53
+ # Policy: We complain iff:
54
+ #
55
+ # a file is added to
56
+ # that is in the three complained about
57
+ # and the total ends up above 300
58
+ #
59
+ # ...and we only complain once per file
60
+ context 'when single file net added to ' \
61
+ 'that is one of the three complained about, ' \
62
+ 'and is above limit' do
63
+ let(:expected_output) do
64
+ "one_line_added_above_limit.rb:302 W: This file, one of the " \
65
+ "3 largest in the project, increased in size to 302 lines. " \
66
+ "The total size of those files is now 502 lines (target: 300). " \
67
+ "Is this file complex enough to refactor?\n"
68
+ end
69
+
70
+ let(:example_files_committed) do
71
+ {
72
+ 'one_line_added_above_limit.rb' => ("\n" * 301),
73
+ 'some_other_file_1.rb' => ("\n" * 100),
74
+ 'some_other_file_2.rb' => ("\n" * 100),
75
+ }
76
+ end
77
+
78
+ let(:example_files_staged) do
79
+ { 'one_line_added_above_limit.rb' => ("\n" * 302) }
80
+ end
81
+
82
+ it 'complains on line of first change' do
83
+ expect(out).to eq(expected_output)
84
+ expect(exit_code).to eq(0)
85
+ end
86
+ end
87
+ end
88
+ end
File without changes
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pronto'
4
+
5
+ module Pronto
6
+ # Performs incremental quality reporting for the bigfiles gem
7
+ class BigFiles < Runner
8
+ # Creates Pronto warning message objects
9
+ class MessageCreator
10
+ attr_reader :num_files, :total_lines, :target_num_lines
11
+
12
+ def initialize(num_files, total_lines, target_num_lines)
13
+ @num_files = num_files
14
+ @total_lines = total_lines
15
+ @target_num_lines = target_num_lines
16
+ end
17
+
18
+ def create_message(patch_wrapper, num_lines)
19
+ path = patch_wrapper.path
20
+ line = patch_wrapper.first_added_line
21
+ level = :warning
22
+ msg = "This file, one of the #{num_files} largest in the project, " \
23
+ "increased in size to #{num_lines} lines. The total size " \
24
+ "of those files is now #{total_lines} lines " \
25
+ "(target: #{target_num_lines}). Is this file complex " \
26
+ "enough to refactor?"
27
+ Message.new(path, line, level, msg)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pronto'
4
+ require_relative 'message_creator'
5
+
6
+ module Pronto
7
+ # Performs incremental quality reporting for the bigfiles gem
8
+ class BigFiles < Runner
9
+ # Inspects patches and returns a Pronto::Message class when appropriate
10
+ class PatchInspector
11
+ def initialize(bigfiles_result,
12
+ message_creator_class: MessageCreator,
13
+ bigfiles_config:)
14
+ @message_creator_class = message_creator_class
15
+ @bigfiles_result = bigfiles_result
16
+ @bigfiles_config = bigfiles_config
17
+ @message_creator =
18
+ @message_creator_class.new(@bigfiles_config.num_files,
19
+ total_lines,
20
+ @bigfiles_config.high_water_mark)
21
+ end
22
+
23
+ def under_limit?
24
+ @bigfiles_config.under_limit?(total_lines)
25
+ end
26
+
27
+ def total_lines
28
+ @bigfiles_result.map(&:num_lines).reduce(:+)
29
+ end
30
+
31
+ def inspect_patch(patch_wrapper)
32
+ path = patch_wrapper.path
33
+ file_with_line = @bigfiles_result.find { |f| f.filename == path }
34
+
35
+ return if file_with_line.nil?
36
+
37
+ return unless patch_wrapper.added_to?
38
+
39
+ return if under_limit?
40
+
41
+ @message_creator.create_message(patch_wrapper, file_with_line.num_lines)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pronto'
4
+
5
+ module Pronto
6
+ class BigFiles < Runner
7
+ # Add convenience methods on top of Pronto::Git::Patch
8
+ class PatchWrapper
9
+ attr_reader :patch
10
+
11
+ def initialize(patch)
12
+ @patch = patch
13
+ end
14
+
15
+ def added_to?
16
+ (patch.additions - patch.deletions).positive?
17
+ end
18
+
19
+ def path
20
+ patch.delta.new_file[:path]
21
+ end
22
+
23
+ def first_added_line
24
+ patch.added_lines.first
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pronto
4
+ module BigFilesVersion
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pronto/bigfiles/version'
4
+ require 'pronto/bigfiles/patch_inspector'
5
+ require 'pronto/bigfiles/patch_wrapper'
6
+ require 'bigfiles/inspector'
7
+ require 'bigfiles/config'
8
+ require 'pronto'
9
+
10
+ module Pronto
11
+ # Performs incremental quality reporting for the bigfiles gem
12
+ class BigFiles < Runner
13
+ def initialize(patches, commit = nil,
14
+ bigfiles_config: ::BigFiles::Config.new,
15
+ bigfiles_inspector: ::BigFiles::Inspector.new,
16
+ bigfiles_results: bigfiles_inspector.find_and_analyze,
17
+ patch_wrapper_class: PatchWrapper,
18
+ patch_inspector: PatchInspector.new(bigfiles_results,
19
+ bigfiles_config:
20
+ bigfiles_config))
21
+ super(patches, commit)
22
+ @patch_inspector = patch_inspector
23
+ @patch_wrapper_class = patch_wrapper_class
24
+ end
25
+
26
+ class Error < StandardError; end
27
+ def run
28
+ @patches.flat_map { |patch| inspect_patch(patch) }
29
+ end
30
+
31
+ def inspect_patch(patch)
32
+ @patch_inspector.inspect_patch(@patch_wrapper_class.new(patch))
33
+ end
34
+ end
35
+ end
@@ -0,0 +1 @@
1
+ 300
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1 @@
1
+ 0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/pronto/bigfiles/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'pronto-bigfiles'
7
+ spec.version = Pronto::BigFilesVersion::VERSION
8
+ spec.authors = ['Vince Broz']
9
+ spec.email = ['vince@broz.cc']
10
+
11
+ spec.summary = 'Pronto plugin for the bigfiles gem'
12
+ spec.description = <<~DESCRIPTION
13
+ Performs incremental quality reporting for the bigfiles gem.
14
+ BigFiles is a simple tool to find the largest source files in your
15
+ project; this gem plugs in with the 'pronto' gem, which does
16
+ incremental reporting using a variety of quality tools.
17
+ DESCRIPTION
18
+ spec.homepage = 'https://github.com/apiology/pronto-bigfiles'
19
+ spec.license = 'MIT'
20
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
21
+
22
+ spec.metadata['homepage_uri'] = spec.homepage
23
+ spec.metadata['source_code_uri'] =
24
+ 'https://github.com/apiology/pronto-bigfiles'
25
+
26
+ # Specify which files should be added to the gem when it is
27
+ # released. The `git ls-files -z` loads the files in the RubyGem
28
+ # that have been added into git.
29
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
30
+ `git ls-files -z`.split("\x0").reject do |f|
31
+ f.match(%r{^(test|spec|features)/})
32
+ end
33
+ end
34
+ spec.bindir = 'exe'
35
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ['lib']
37
+
38
+ spec.add_dependency 'bigfiles', '>=0.2.0'
39
+ spec.add_dependency 'pronto'
40
+ spec.add_dependency 'quality', '>= 37'
41
+
42
+ spec.add_development_dependency 'bundler', '~> 2.0'
43
+ spec.add_development_dependency 'pronto-punchlist'
44
+ spec.add_development_dependency 'pronto-rubocop'
45
+ spec.add_development_dependency 'quality', '~> 37'
46
+ spec.add_development_dependency 'rake'
47
+ spec.add_development_dependency 'rspec'
48
+ spec.add_development_dependency 'simplecov'
49
+ end
data/rakelib/ci.rake ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Run tasks to be done during a continuous integration (CI) build'
4
+ task ci: :localtest
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Rebaseline quality thresholds to last commit'
4
+ task :clear_metrics do |_t|
5
+ ret =
6
+ system('git checkout coverage/.last_run.json metrics/*_high_water_mark')
7
+ raise unless ret
8
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ task default: :localtest
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Run features'
6
+ RSpec::Core::RakeTask.new(:feature) do |task|
7
+ task.pattern = 'feature/**/*_spec.rb'
8
+ task.rspec_opts = '--format doc --default-path feature'
9
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Standard build when running on a workstation'
4
+ task localtest: %i[clear_metrics spec feature quality]
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Look for incremental quality issues'
4
+ task :pronto do
5
+ formatter = '-f github_pr' if ENV.key? 'PRONTO_GITHUB_ACCESS_TOKEN'
6
+ if ENV.key? 'TRAVIS_PULL_REQUEST'
7
+ ENV['PRONTO_PULL_REQUEST_ID'] = ENV['TRAVIS_PULL_REQUEST']
8
+ elsif ENV.key? 'CIRCLE_PULL_REQUEST'
9
+ ENV['PRONTO_PULL_REQUEST_ID'] = ENV['CIRCLE_PULL_REQUEST'].split('/').last
10
+ end
11
+ sh "pronto run #{formatter} -c origin/master --no-exit-code --unstaged "\
12
+ "|| true"
13
+ sh "pronto run #{formatter} -c origin/master --no-exit-code --staged || true"
14
+ sh "pronto run #{formatter} -c origin/master --no-exit-code || true"
15
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'quality/rake/task'
4
+
5
+ Quality::Rake::Task.new do |task|
6
+ task.exclude_files = ['Gemfile.lock']
7
+ # cane deprecated in favor of rubocop, reek rarely actionable
8
+ task.skip_tools = %w[reek cane eslint jscs flake8]
9
+ task.output_dir = 'metrics'
10
+ task.punchlist_regexp = 'XX' \
11
+ 'X|TOD' \
12
+ 'O|FIXM' \
13
+ 'E|OPTIMIZ' \
14
+ 'E|HAC' \
15
+ 'K|REVIE' \
16
+ 'W|LATE' \
17
+ 'R|FIXI' \
18
+ 'T|xi' \
19
+ 't '
20
+ end
21
+
22
+ desc 'Static analysis and metrics enforcement'
23
+ task quality: %i[pronto update_bundle_audit]
data/rakelib/spec.rake ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Run specs'
6
+ RSpec::Core::RakeTask.new(:spec) do |task|
7
+ task.pattern = 'spec/**/*_spec.rb'
8
+ task.rspec_opts = '--format doc'
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Update definitions used in bundle-audit'
4
+ task :update_bundle_audit do
5
+ sh 'bundle-audit update'
6
+ end