danger-wcc 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -2
  3. data/.rubocop.yml +24 -17
  4. data/README.md +2 -0
  5. data/danger-wcc.gemspec +4 -4
  6. data/lib/version.rb +1 -1
  7. data/lib/wcc/commit_lint.rb +2 -1
  8. data/lib/wcc/commit_lint/commit_check.rb +0 -1
  9. data/lib/wcc/commit_lint/empty_line_check.rb +0 -1
  10. data/lib/wcc/commit_lint/subject_cap_check.rb +0 -1
  11. data/lib/wcc/commit_lint/subject_length_check.rb +0 -1
  12. data/lib/wcc/commit_lint/subject_period_check.rb +0 -1
  13. data/lib/wcc/commit_lint/subject_words_check.rb +0 -1
  14. data/lib/wcc/defaults.reek +8 -8
  15. data/lib/wcc/dependencies.rb +74 -0
  16. data/lib/wcc/dependencies/yarn_info.rb +83 -0
  17. data/lib/wcc/jshint.rb +2 -2
  18. data/lib/wcc/plugin.rb +21 -11
  19. data/lib/wcc/reek.rb +2 -2
  20. data/lib/wcc/rubocop_exceptions.rb +13 -8
  21. data/lib/wcc/todos.rb +5 -4
  22. data/lib/wcc/utils.rb +17 -5
  23. data/spec/fixtures/dependencies/package.json +112 -0
  24. data/spec/fixtures/dependencies/package.json.diff +28 -0
  25. data/spec/fixtures/dependencies/package.json_patch_bumps_minor.diff +13 -0
  26. data/spec/fixtures/dependencies/package.json_patch_bumps_minor.json +112 -0
  27. data/spec/fixtures/dependencies/yarn.lock +19609 -0
  28. data/spec/fixtures/dependencies/yarn.lock_patch_bumps_minor.lock +19614 -0
  29. data/spec/fixtures/dependencies/yarn_minor_version.diff +33 -0
  30. data/spec/fixtures/dependencies/yarn_minor_version.txt +1151 -0
  31. data/spec/fixtures/dependencies/yarn_old.txt +1152 -0
  32. data/spec/fixtures/dependencies/yarn_patch_bumps_minor.diff +28 -0
  33. data/spec/fixtures/exception_inline_disabled_rule.diff +12 -0
  34. data/spec/fixtures/rubocop_exception.rb +3 -0
  35. data/spec/fixtures_helper.rb +0 -1
  36. data/spec/spec_helper.rb +1 -1
  37. data/spec/wcc/commit_lint_spec.rb +6 -10
  38. data/spec/wcc/dependencies_spec.rb +95 -0
  39. data/spec/wcc/github_spec.rb +13 -7
  40. data/spec/wcc/jshint_spec.rb +1 -1
  41. data/spec/wcc/plugin_spec.rb +18 -17
  42. data/spec/wcc/reek_spec.rb +1 -1
  43. data/spec/wcc/rubocop_exceptions_spec.rb +34 -15
  44. data/spec/wcc/todos_spec.rb +10 -10
  45. data/spec/wcc/utils_spec.rb +2 -2
  46. data/spec/wcc_spec.rb +1 -1
  47. metadata +49 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 668121398555f8e999832607cf9320125a2252d5
4
- data.tar.gz: 514a28d49ea478d5491079c155eddf35ea6f7b40
3
+ metadata.gz: 356af9ca6ebc46af86c402709d820bb30fd94c1e
4
+ data.tar.gz: 6842e1bc5330f0088b2978c58e9c9e85afab2030
5
5
  SHA512:
6
- metadata.gz: fb3394ddf30b674ab2652b728cbea2ae27978784f1747d380c4fa07cc75a1db60976fcfc365cc8693ebbaeffd496e64b79ed28a4290422a2fc661c192dcb3f22
7
- data.tar.gz: 100ebecf8ec74cbe6d850244ef9d943c307acf26ea10e3ea5d8de57b3701660b41b7df7940f9bdb62544ce4f506fb16552f2001d3b6861ee10f87079cdf6381a
6
+ metadata.gz: 5c31ffdd4c4cdc7f4a7c8f1631816d6f1452ba31bc0a03d8a5e1c392265ef8b29decd9e644d2f5b437b4ec2d3a282d7973a2f2d81b8fe1c9d02c84e8c3315523
7
+ data.tar.gz: 9d8fecdeaab1eda89620ac77454c28b9975987fb5a875ce472bae1e8ba2fdac511b54dbfe0647c46ef6c7f3fccdfc9b501a5ca24fbc85c016328e26108445842
@@ -9,14 +9,14 @@ jobs:
9
9
  - checkout
10
10
  # Restore bundle cache
11
11
  - restore_cache:
12
- key: rails-{{ checksum "Gemfile.lock" }}
12
+ key: rails-{{ checksum "danger-wcc.gemspec" }}
13
13
 
14
14
  # Bundle install dependencies
15
15
  - run: bundle install --path /tmp/vendor/bundle
16
16
 
17
17
  # Store bundle cache
18
18
  - save_cache:
19
- key: rails-{{ checksum "Gemfile.lock" }}
19
+ key: rails-{{ checksum "danger-wcc.gemspec" }}
20
20
  paths:
21
21
  - /tmp/vendor/bundle
22
22
 
@@ -2,6 +2,7 @@ AllCops:
2
2
  DisplayCopNames: true
3
3
  TargetRubyVersion: 2.3
4
4
  Exclude:
5
+ - 'spec/fixtures/**/*'
5
6
  # generated by rails/binstubs
6
7
  - 'bin/**/*'
7
8
 
@@ -31,7 +32,7 @@ Style/FormatStringToken:
31
32
  Metrics/BlockLength:
32
33
  Exclude:
33
34
  # config files where we expect long blocks
34
- - 'danger-wm.gemspec'
35
+ - 'danger-wcc.gemspec'
35
36
  # spec files that might have a big describe
36
37
  - 'spec/**/*.rb'
37
38
  # dsl files https://stackoverflow.com/a/41187163
@@ -43,29 +44,39 @@ Metrics/MethodLength:
43
44
 
44
45
  Metrics/ModuleLength:
45
46
  Exclude:
46
- - 'lib/wm/utils.rb'
47
+ - 'lib/wcc/utils.rb'
47
48
  - 'spec/**/*.rb'
48
49
 
49
- Performance/HashEachMethods:
50
- Exclude:
51
- - 'spec/**/*.rb'
52
-
53
- Performance/UnfreezeString:
54
- Exclude:
55
- - 'spec/**/*.rb'
50
+ Naming/MethodParameterName:
51
+ Enabled: false
56
52
 
57
- Style/BracesAroundHashParameters:
53
+ Naming/MemoizedInstanceVariableName:
58
54
  Enabled: false
59
55
 
60
56
  Lint/AssignmentInCondition:
61
57
  Enabled: false
62
58
 
59
+ Lint/RaiseException:
60
+ Enabled: true
61
+
62
+ Lint/StructNewOverride:
63
+ Enabled: true
64
+
63
65
  Style/EmptyMethod:
64
66
  EnforcedStyle: expanded
65
67
 
66
68
  Style/Alias:
67
69
  EnforcedStyle: prefer_alias_method
68
70
 
71
+ Style/HashEachMethods:
72
+ Enabled: true
73
+
74
+ Style/HashTransformKeys:
75
+ Enabled: true
76
+
77
+ Style/HashTransformValues:
78
+ Enabled: true
79
+
69
80
  Style/NumericPredicate:
70
81
  EnforcedStyle: comparison
71
82
 
@@ -76,13 +87,13 @@ Style/RegexpLiteral:
76
87
  Style/SignalException:
77
88
  Enabled: false
78
89
 
79
- Layout/AlignParameters:
90
+ Layout/ParameterAlignment:
80
91
  EnforcedStyle: with_fixed_indentation
81
92
 
82
- Layout/IndentHash:
93
+ Layout/FirstHashElementIndentation:
83
94
  EnforcedStyle: consistent
84
95
 
85
- Layout/AlignHash:
96
+ Layout/HashAlignment:
86
97
  # allow coder to get around alignment rules by explicitly defining the hash param
87
98
  EnforcedLastArgumentHashStyle: ignore_explicit
88
99
 
@@ -124,10 +135,6 @@ Layout/MultilineAssignmentLayout:
124
135
  StyleGuide: '#indent-conditional-assignment'
125
136
  Enabled: true
126
137
 
127
- Lint/UnneededDisable:
128
- Exclude:
129
- - 'spec/fixtures/**/*'
130
-
131
138
  Lint/MissingCopEnableDirective:
132
139
  Exclude:
133
140
  - 'spec/fixtures/**/*'
data/README.md CHANGED
@@ -1,2 +1,4 @@
1
+ ![Build Status](https://circleci.com/gh/watermarkchurch/danger-wcc.svg?&style=shield&circle-token=87f4572e4fd1982dcbefc9feca233865955eb9e7)
2
+
1
3
  Copyright (c) 2018 Watermark Community Church
2
4
  all rights reserved
@@ -1,7 +1,6 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
5
  require 'version'
7
6
 
@@ -20,10 +19,11 @@ Gem::Specification.new do |spec|
20
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
20
  spec.require_paths = ['lib']
22
21
 
22
+ spec.add_runtime_dependency 'activesupport', '> 5'
23
23
  spec.add_runtime_dependency 'brakeman'
24
24
  spec.add_runtime_dependency 'danger-plugin-api', '~> 1.0'
25
25
  spec.add_runtime_dependency 'flay'
26
- spec.add_runtime_dependency 'git_diff', '~> 0.3'
26
+ spec.add_runtime_dependency 'git_diff', '~> 0.4'
27
27
  spec.add_runtime_dependency 'reek'
28
28
 
29
29
  # General ruby development
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency 'webmock', '~> 3.1'
37
37
 
38
38
  # Linting code and docs
39
- spec.add_development_dependency 'rubocop'
39
+ spec.add_development_dependency 'rubocop', '~> 0.81'
40
40
  spec.add_development_dependency 'yard'
41
41
 
42
42
  # Makes testing easy via `bundle exec guard`
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DangerWCC
4
- VERSION = '0.0.2'
4
+ VERSION = '0.1.0'
5
5
  end
@@ -102,7 +102,7 @@ class Danger::DangerWCC < Danger::Plugin
102
102
  return unless c.fail?
103
103
 
104
104
  messaging.issue([c.message, message[:sha]].join("\n"),
105
- severity: severity)
105
+ severity: severity)
106
106
  end
107
107
 
108
108
  def checkers
@@ -141,6 +141,7 @@ class Danger::DangerWCC < Danger::Plugin
141
141
 
142
142
  def warning_checks
143
143
  return checks if @config[:warn] == :all
144
+
144
145
  @config[:warn] || []
145
146
  end
146
147
 
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class CommitCheck
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class EmptyLineCheck < CommitCheck
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class SubjectCapCheck < CommitCheck
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class SubjectLengthCheck < CommitCheck
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class SubjectPeriodCheck < CommitCheck
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class SubjectWordsCheck < CommitCheck
@@ -23,10 +23,10 @@ DuplicateMethodCall:
23
23
  allow_calls: []
24
24
  FeatureEnvy:
25
25
  enabled: true
26
- exclude: []
26
+ exclude: ["Helper"]
27
27
  InstanceVariableAssumption:
28
28
  enabled: true
29
- exclude: []
29
+ exclude: ["Controller"]
30
30
  IrresponsibleModule:
31
31
  enabled: false
32
32
  exclude: []
@@ -54,7 +54,7 @@ NestedIterators:
54
54
  ignore_iterators:
55
55
  - tap
56
56
  NilCheck:
57
- enabled: true
57
+ enabled: false
58
58
  exclude: []
59
59
  PrimaDonnaMethod:
60
60
  enabled: true
@@ -70,15 +70,15 @@ Syntax:
70
70
  enabled: true
71
71
  exclude: []
72
72
  TooManyConstants:
73
- enabled: false
73
+ enabled: true
74
74
  exclude: []
75
75
  max_constants: 5
76
76
  TooManyInstanceVariables:
77
- enabled: false
77
+ enabled: true
78
78
  exclude: []
79
79
  max_instance_variables: 5
80
80
  TooManyMethods:
81
- enabled: false
81
+ enabled: true
82
82
  exclude: []
83
83
  max_methods: 15
84
84
  TooManyStatements:
@@ -127,5 +127,5 @@ UnusedPrivateMethod:
127
127
  exclude: []
128
128
  UtilityFunction:
129
129
  enabled: true
130
- exclude: []
131
- public_methods_only: false
130
+ exclude: ["Helper", "util"]
131
+ public_methods_only: true
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require_relative 'utils'
5
+
6
+ class Danger::DangerWCC < Danger::Plugin
7
+ class Dependencies
8
+ include Utils
9
+
10
+ def yarn_info
11
+ @yarn_info ||= YarnInfo.new(self) if File.exist?('yarn.lock')
12
+ end
13
+
14
+ def initialize(plugin, options = {})
15
+ @plugin = plugin
16
+ @options = options
17
+ end
18
+
19
+ def perform
20
+ return unless File.exist?('yarn.lock')
21
+
22
+ find_yarn_violations
23
+ end
24
+
25
+ private
26
+
27
+ def issue_yarn_violation(package, versions)
28
+ line_index = yarn_info.find_index_in_lockfile(package, versions[1])
29
+
30
+ plugin.fail "Dangerous change! #{package} was updated "\
31
+ "from #{versions[0]} to #{versions[1]}"\
32
+ ' without a corresponding change to package.json!',
33
+ file: 'yarn.lock', line: line_index
34
+ end
35
+
36
+ def find_yarn_violations # rubocop:disable Metrics/AbcSize
37
+ # if there's a corresponding change in the package.json, ignore
38
+ mods =
39
+ yarn_info.modified_yarn_dependencies
40
+ .except(*yarn_info.package_json_changes)
41
+ .select { |_, versions| dangerous_change?(versions[0], versions[1]) }
42
+
43
+ has_dangerous_top_level_changes = false
44
+ # issue warnings for top level dependencies
45
+ mods.slice(*yarn_info.package_json_dependencies)
46
+ .each do |package, versions|
47
+ has_dangerous_top_level_changes = true
48
+ issue_yarn_violation(package, versions)
49
+ end
50
+ # issue warnings if a sub-dependency changed without a dangerous change in
51
+ # a top level dependency
52
+ return if has_dangerous_top_level_changes
53
+
54
+ mods.except(*yarn_info.package_json_dependencies)
55
+ .each do |package, versions|
56
+ issue_yarn_violation(package, versions)
57
+ end
58
+ end
59
+
60
+ def dangerous_change?(old_version, new_version)
61
+ # the package was deleted
62
+ return true unless new_version
63
+
64
+ old_segments = old_version.segments
65
+ new_segments = new_version.segments
66
+
67
+ # the major or minor version changed.
68
+ new_segments[0] > old_segments[0] ||
69
+ new_segments[1] > old_segments[1]
70
+ end
71
+ end
72
+ end
73
+
74
+ require_relative 'dependencies/yarn_info'
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Danger::DangerWCC::Dependencies
4
+ class YarnInfo
5
+ def yarn_lock
6
+ @yarn_lock ||= File.readlines('yarn.lock')
7
+ end
8
+
9
+ def package_json_dependencies
10
+ @package_json_dependencies ||=
11
+ JSON.parse(File.read('package.json'))['dependencies']&.keys || []
12
+ end
13
+
14
+ def package_json_changes
15
+ @package_json_changes ||= find_package_json_changes
16
+ end
17
+
18
+ def modified_yarn_dependencies
19
+ @modified_yarn_dependencies ||= find_modified_yarn_packages
20
+ end
21
+
22
+ attr_reader :plugin
23
+
24
+ def initialize(plugin)
25
+ @plugin = plugin
26
+ end
27
+
28
+ def find_index_in_lockfile(package, version)
29
+ return 0 unless version
30
+
31
+ re = Regexp.new("^#{Regexp.escape(package)}@", Regexp::IGNORECASE)
32
+ indexes =
33
+ yarn_lock.each_with_index
34
+ .select { |l, _i| re.match(l) }
35
+ .map { |pair| pair[1] }
36
+ idx =
37
+ indexes.find do |i|
38
+ yarn_lock[i + 1].include?("version \"#{version}\"")
39
+ end
40
+ (idx || -1) + 1
41
+ end
42
+
43
+ def parse_yarn_semver(line)
44
+ match = /(?<package>\S+)\@(?<version>\S+)/.match(line)
45
+ [match['package'], Gem::Version.new(match['version'])] if match
46
+ end
47
+
48
+ private
49
+
50
+ def find_package_json_changes
51
+ return [] unless file = plugin.find_file_in_diff('package.json')
52
+
53
+ adds = file.hunks.flat_map { |h| h.lines.select(&:addition?) }
54
+ adds.map { |l| /\"(?<package>\S+)\"\: \"\S+\"/.match(l.content) }
55
+ .compact
56
+ .map { |match| match['package'] }
57
+ end
58
+
59
+ def find_modified_yarn_packages # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
60
+ diff = plugin.run_and_diff(
61
+ 'NODE_ENV=production yarn list --depth 0 2>/dev/null'
62
+ )
63
+ diff = GitDiff.from_string(diff)
64
+
65
+ {}.tap do |modified_packages|
66
+ plugin.each_file_in_diff(diff) do |file, _diff|
67
+ file.hunks.each do |hunk|
68
+ deleted, added =
69
+ %i[deletion? addition?].map do |type|
70
+ Hash[hunk.lines.select { |l| l.public_send(type) }
71
+ .map { |l| parse_yarn_semver(l.content) }
72
+ .compact]
73
+ end
74
+ deleted.each do |(package, version)|
75
+ modified_packages[package] =
76
+ [version, added[package]]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -56,8 +56,8 @@ class Danger::DangerWCC < Danger::Plugin
56
56
  )
57
57
 
58
58
  plugin.warn(warning.captures[2],
59
- file: warning.captures[0],
60
- line: warning.captures[1].to_i)
59
+ file: warning.captures[0],
60
+ line: warning.captures[1].to_i)
61
61
  end
62
62
  end
63
63
  end
@@ -7,28 +7,33 @@ require_relative 'rubocop_exceptions'
7
7
  require_relative 'commit_lint'
8
8
  require_relative 'reek'
9
9
  require_relative 'jshint'
10
+ require_relative 'dependencies'
10
11
 
11
12
  class Danger::DangerWCC < Danger::Plugin
12
13
  include Utils
13
14
  include Github
14
15
 
15
- CHECKS = %i[
16
- rubocop_exceptions
17
- todos
18
- commit_lint
19
- reek
20
- flay
21
- brakeman
22
- jshint
23
- ].freeze
16
+ DEFAULT_OPTIONS = {
17
+ rubocop_exceptions: true,
18
+ flay: true,
19
+ todos: true,
20
+ brakeman: true,
21
+ commit_lint: false,
22
+ reek: false,
23
+ jshint: false,
24
+ dependencies: true
25
+ }.freeze
24
26
 
25
27
  # Runs all the included checks in the plugin
26
28
  def all(options = {})
27
- to_run = CHECKS.reject { |check_name| options[check_name] == false }
29
+ options = DEFAULT_OPTIONS.merge(options)
30
+
31
+ to_run = options.keys.reject { |check_name| options[check_name] == false }
28
32
  raise ArgumentError, 'No Enabled Checks' if to_run.empty?
29
33
 
30
34
  to_run.each do |check_name|
31
- public_send(check_name, options.fetch(check_name, {}))
35
+ check_options = options.fetch(check_name, {})
36
+ public_send(check_name, check_options == true ? {} : check_options)
32
37
  end
33
38
  end
34
39
 
@@ -92,6 +97,11 @@ class Danger::DangerWCC < Danger::Plugin
92
97
  Jshint.new(self, options).perform
93
98
  end
94
99
 
100
+ def dependencies(options = {})
101
+ logger.info "dependencies: #{options}"
102
+ Dependencies.new(self, options).perform
103
+ end
104
+
95
105
  private
96
106
 
97
107
  def parse_flay_results