license_finder 6.14.2 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.rubocop.yml +12 -2
  4. data/CHANGELOG.md +35 -4
  5. data/Dockerfile +26 -5
  6. data/README.md +30 -27
  7. data/Rakefile +2 -2
  8. data/VERSION +1 -1
  9. data/ci/pipelines/release.yml.erb +1 -1
  10. data/ci/scripts/pushscript.sh +2 -3
  11. data/ci/scripts/run-tests.sh +4 -3
  12. data/ci/tasks/rubocop.yml +1 -1
  13. data/dlf +9 -5
  14. data/lib/license_finder/cli/approvals.rb +2 -2
  15. data/lib/license_finder/cli/base.rb +9 -5
  16. data/lib/license_finder/cli/dependencies.rb +4 -4
  17. data/lib/license_finder/cli/ignored_dependencies.rb +3 -3
  18. data/lib/license_finder/cli/ignored_groups.rb +3 -3
  19. data/lib/license_finder/cli/inherited_decisions.rb +5 -5
  20. data/lib/license_finder/cli/licenses.rb +2 -2
  21. data/lib/license_finder/cli/main.rb +17 -11
  22. data/lib/license_finder/cli/permitted_licenses.rb +3 -3
  23. data/lib/license_finder/cli/project_name.rb +4 -4
  24. data/lib/license_finder/cli/restricted_licenses.rb +3 -3
  25. data/lib/license_finder/configuration.rb +6 -3
  26. data/lib/license_finder/core.rb +2 -1
  27. data/lib/license_finder/decisions.rb +9 -5
  28. data/lib/license_finder/license/definitions.rb +22 -0
  29. data/lib/license_finder/license/text.rb +5 -3
  30. data/lib/license_finder/license.rb +8 -2
  31. data/lib/license_finder/logger.rb +1 -1
  32. data/lib/license_finder/package.rb +3 -11
  33. data/lib/license_finder/package_delta.rb +1 -1
  34. data/lib/license_finder/package_manager.rb +1 -0
  35. data/lib/license_finder/package_managers/cocoa_pods.rb +14 -9
  36. data/lib/license_finder/package_managers/conan.rb +2 -2
  37. data/lib/license_finder/package_managers/conda.rb +1 -1
  38. data/lib/license_finder/package_managers/glide.rb +7 -1
  39. data/lib/license_finder/package_managers/go_15vendorexperiment.rb +2 -2
  40. data/lib/license_finder/package_managers/go_dep.rb +1 -1
  41. data/lib/license_finder/package_managers/go_workspace.rb +1 -1
  42. data/lib/license_finder/package_managers/maven.rb +2 -6
  43. data/lib/license_finder/package_managers/nuget.rb +1 -1
  44. data/lib/license_finder/package_managers/pub.rb +86 -0
  45. data/lib/license_finder/package_managers/sbt.rb +1 -5
  46. data/lib/license_finder/package_managers/yarn.rb +48 -9
  47. data/lib/license_finder/package_utils/license_files.rb +2 -2
  48. data/lib/license_finder/packages/bower_package.rb +5 -2
  49. data/lib/license_finder/packages/erlangmk_package.rb +2 -4
  50. data/lib/license_finder/packages/npm_package.rb +1 -0
  51. data/lib/license_finder/packages/pubspec_package.rb +18 -0
  52. data/lib/license_finder/printer.rb +39 -0
  53. data/lib/license_finder/report.rb +2 -1
  54. data/lib/license_finder/reports/csv_report.rb +1 -1
  55. data/lib/license_finder/reports/erb_report.rb +7 -3
  56. data/lib/license_finder/reports/json_report.rb +2 -1
  57. data/lib/license_finder/reports/junit_report.rb +5 -1
  58. data/lib/license_finder/reports/xml_report.rb +5 -1
  59. data/lib/license_finder/scanner.rb +1 -1
  60. data/license_finder.gemspec +15 -13
  61. metadata +58 -26
@@ -38,7 +38,7 @@ module LicenseFinder
38
38
  project_path.join(GODEP_VENDOR_PATH)
39
39
  else
40
40
  download_dependencies
41
- Pathname(ENV['GOPATH'] ? ENV['GOPATH'] + '/src' : ENV['HOME'] + '/go/src')
41
+ Pathname(ENV['GOPATH'] ? "#{ENV['GOPATH']}/src" : "#{ENV['HOME']}/go/src")
42
42
  end
43
43
  end
44
44
 
@@ -94,7 +94,7 @@ module LicenseFinder
94
94
  deps = val.split("\n")
95
95
  Cmd.run('go list std').first.split("\n").each do |std|
96
96
  deps.delete_if do |dep|
97
- dep =~ %r{(\/|^)#{std}(\/|$)}
97
+ dep =~ %r{(/|^)#{std}(/|$)}
98
98
  end
99
99
  end
100
100
  deps
@@ -34,14 +34,10 @@ module LicenseFinder
34
34
  end
35
35
 
36
36
  def package_management_command
37
- wrapper = if Platform.windows?
38
- 'mvnw.cmd'
39
- else
40
- './mvnw'
41
- end
37
+ wrapper = File.join(project_path, Platform.windows? ? 'mvnw.cmd' : 'mvnw')
42
38
  maven = 'mvn'
43
39
 
44
- File.exist?(File.join(project_path, wrapper)) ? wrapper : maven
40
+ File.exist?(wrapper) ? wrapper : maven
45
41
  end
46
42
 
47
43
  def possible_package_paths
@@ -64,7 +64,7 @@ module LicenseFinder
64
64
 
65
65
  file = files.first
66
66
  Zip::File.open file do |zipfile|
67
- content = zipfile.read(dep.name + '.nuspec')
67
+ content = zipfile.read("#{dep.name}.nuspec")
68
68
  Nuget.nuspec_license_urls(content)
69
69
  end
70
70
  end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'yaml'
5
+
6
+ module LicenseFinder
7
+ class Pub < PackageManager
8
+ class PubError < RuntimeError; end
9
+
10
+ def current_packages
11
+ unless File.exist?('pubspec.lock')
12
+ raise PubError, "No checked-out Pub packages found.
13
+ Please install your dependencies first."
14
+ end
15
+
16
+ if ENV['PUB_CACHE'].nil? || ENV['PUB_CACHE'].eql?('')
17
+ raise PubError, 'While PUB_CACHE environment variable is empty, retrieving package licenses is impossible. Please set the PUB_CACHE env variable (default: ~/.pub)'
18
+ end
19
+
20
+ stdout, _stderr, _status = Cmd.run('flutter pub deps --json')
21
+ yaml_deps = JSON.parse(stdout)
22
+ yaml_deps['packages'].map do |dependency|
23
+ package_name = dependency['name']
24
+ subpath = "#{dependency['name']}-#{dependency['version']}"
25
+ package_version = dependency['version']
26
+
27
+ project_repo = dependency['source'] == 'git' ? Pathname("#{ENV['PUB_CACHE']}/git/#{dependency['name']}-*/") : Pathname("#{ENV['PUB_CACHE']}/hosted/pub.dartlang.org/#{subpath}")
28
+
29
+ homepage = read_repository_home(project_repo)
30
+ homepage = "https://pub.dev/packages/#{package_name}" if homepage.nil? || homepage.empty?
31
+ PubPackage.new(
32
+ package_name,
33
+ package_version,
34
+ license_text(project_repo),
35
+ logger: logger,
36
+ install_path: project_repo,
37
+ homepage: homepage
38
+ )
39
+ end
40
+ end
41
+
42
+ def possible_package_paths
43
+ [project_path.join('pubspec.lock')]
44
+ end
45
+
46
+ def package_management_command
47
+ 'flutter'
48
+ end
49
+
50
+ def prepare_command
51
+ 'flutter pub get'
52
+ end
53
+
54
+ def prepare
55
+ prep_cmd = "#{prepare_command} #{production_flag}"
56
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
57
+
58
+ return if status.success?
59
+
60
+ log_errors stderr
61
+ raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
62
+ end
63
+
64
+ private
65
+
66
+ def license_text(subpath)
67
+ license_path = license_pattern(subpath).find { |f| File.exist?(f) }
68
+ license_path.nil? ? nil : IO.read(license_path)
69
+ end
70
+
71
+ def license_pattern(subpath)
72
+ Dir.glob(subpath.join('LICENSE*'), File::FNM_CASEFOLD)
73
+ end
74
+
75
+ def production_flag
76
+ return '' if @ignored_groups.nil?
77
+
78
+ @ignored_groups.include?('devDependencies') ? '' : 'no-'
79
+ end
80
+
81
+ def read_repository_home(project_repo)
82
+ package_yaml = project_repo.join('pubspec.yaml')
83
+ YAML.load(IO.read(package_yaml))['repository'] if Dir.exist?(project_repo) && File.exist?(package_yaml)
84
+ end
85
+ end
86
+ end
@@ -17,11 +17,7 @@ module LicenseFinder
17
17
 
18
18
  dependencies = SbtDependencyFinder.new(project_path).dependencies
19
19
  packages = dependencies.flat_map do |text|
20
- options = {
21
- headers: true
22
- }
23
-
24
- contents = CSV.parse(text, options)
20
+ contents = CSV.parse(text, headers: true)
25
21
  contents.map do |row|
26
22
  group_id, name, version = row['Dependency'].split('#').map(&:strip)
27
23
  spec = {
@@ -2,19 +2,22 @@
2
2
 
3
3
  module LicenseFinder
4
4
  class Yarn < PackageManager
5
- SHELL_COMMAND = 'yarn licenses list --no-progress --json'
5
+ SHELL_COMMAND = 'yarn licenses list --json'
6
6
 
7
7
  def possible_package_paths
8
8
  [project_path.join('yarn.lock')]
9
9
  end
10
10
 
11
11
  def current_packages
12
- cmd = "#{Yarn::SHELL_COMMAND}#{production_flag}"
13
- suffix = " --cwd #{project_path}" unless project_path.nil?
14
- cmd += suffix unless suffix.nil?
12
+ # the licenses plugin supports the classic production flag
13
+ cmd = "#{Yarn::SHELL_COMMAND}#{classic_yarn_production_flag}"
14
+ if yarn_version == 1
15
+ cmd += ' --no-progress'
16
+ cmd += " --cwd #{project_path}" unless project_path.nil?
17
+ end
15
18
 
16
- stdout, _stderr, status = Cmd.run(cmd)
17
- return [] unless status.success?
19
+ stdout, stderr, status = Cmd.run(cmd)
20
+ raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
18
21
 
19
22
  packages = []
20
23
  incompatible_packages = []
@@ -39,7 +42,7 @@ module LicenseFinder
39
42
  end
40
43
 
41
44
  def prepare
42
- prep_cmd = "#{prepare_command}#{production_flag}"
45
+ prep_cmd = prepare_command.to_s
43
46
  _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
44
47
  return if status.success?
45
48
 
@@ -56,11 +59,41 @@ module LicenseFinder
56
59
  end
57
60
 
58
61
  def prepare_command
59
- 'yarn install --ignore-engines --ignore-scripts'
62
+ if yarn_version == 1
63
+ classic_yarn_prepare_command
64
+ else
65
+ yarn_prepare_command
66
+ end
60
67
  end
61
68
 
62
69
  private
63
70
 
71
+ def yarn_prepare_command
72
+ "#{yarn_plugin_production_command}yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/#{yarn_licenses_plugin_version}/bundles/@yarnpkg/plugin-licenses.js"
73
+ end
74
+
75
+ def classic_yarn_prepare_command
76
+ "yarn install --ignore-engines --ignore-scripts#{classic_yarn_production_flag}"
77
+ end
78
+
79
+ def yarn_licenses_plugin_version
80
+ if yarn_version == 2
81
+ 'v0.6.0'
82
+ else
83
+ 'v0.7.2'
84
+ end
85
+ end
86
+
87
+ def yarn_version
88
+ Dir.chdir(project_path) do
89
+ version_string, stderr_str, status = Cmd.run('yarn -v')
90
+ raise "Command 'yarn -v' failed to execute: #{stderr_str}" unless status.success?
91
+
92
+ version = version_string.split('.').map(&:to_i)
93
+ return version[0]
94
+ end
95
+ end
96
+
64
97
  def packages_from_json(json_data)
65
98
  body = json_data['body']
66
99
  head = json_data['head']
@@ -98,10 +131,16 @@ module LicenseFinder
98
131
  all_packages - [yarn_internal_package]
99
132
  end
100
133
 
101
- def production_flag
134
+ def classic_yarn_production_flag
102
135
  return '' if @ignored_groups.nil?
103
136
 
104
137
  @ignored_groups.include?('devDependencies') ? ' --production' : ''
105
138
  end
139
+
140
+ def yarn_plugin_production_command
141
+ return '' if @ignored_groups.nil?
142
+
143
+ @ignored_groups.include?('devDependencies') ? 'yarn plugin import workspace-tools && yarn workspaces focus --all --production && ' : ''
144
+ end
106
145
  end
107
146
  end
@@ -4,7 +4,7 @@ require 'license_finder/package_utils/possible_license_file'
4
4
 
5
5
  module LicenseFinder
6
6
  class LicenseFiles
7
- CANDIDATE_FILE_NAMES = %w[License Licence COPYING README].freeze
7
+ CANDIDATE_FILE_NAMES = %w[LICENSE License license LICENCE Licence licence COPYING copying README readme].freeze
8
8
  CANDIDATE_PATH_WILDCARD = "*{#{CANDIDATE_FILE_NAMES.join(',')}}*"
9
9
 
10
10
  def self.find(install_path, options = {})
@@ -35,7 +35,7 @@ module LicenseFinder
35
35
  def candidate_files_and_dirs
36
36
  return [] if install_path.nil?
37
37
 
38
- Pathname.glob(install_path.join('**', CANDIDATE_PATH_WILDCARD), File::FNM_CASEFOLD)
38
+ Pathname.glob(install_path.join('**', CANDIDATE_PATH_WILDCARD))
39
39
  end
40
40
  end
41
41
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open-uri'
4
-
5
4
  module LicenseFinder
6
5
  class BowerPackage < Package
7
6
  def initialize(bower_module, options = {})
@@ -35,7 +34,11 @@ module LicenseFinder
35
34
  end
36
35
 
37
36
  def package_url
38
- meta = JSON.parse(open("https://registry.bower.io/packages/#{CGI.escape(name)}").read)
37
+ meta = if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5.0')
38
+ JSON.parse(open("https://registry.bower.io/packages/#{CGI.escape(name)}").read)
39
+ else
40
+ JSON.parse(URI.open("https://registry.bower.io/packages/#{CGI.escape(name)}").read)
41
+ end
39
42
  meta['url']
40
43
  end
41
44
  end
@@ -37,9 +37,7 @@ module LicenseFinder
37
37
  end
38
38
 
39
39
  def dep_version
40
- @dep_version ||= begin
41
- dep_version_unformatted.sub(version_prefix_re, '')
42
- end
40
+ @dep_version ||= dep_version_unformatted.sub(version_prefix_re, '')
43
41
  end
44
42
 
45
43
  def dep_repo
@@ -88,7 +86,7 @@ module LicenseFinder
88
86
  def dep_version_valid?
89
87
  return false unless set?(dep_version_unformatted)
90
88
 
91
- if dep_version =~ version_re
89
+ if dep_version&.match?(version_re)
92
90
  Gem::Version.correct?(dep_version)
93
91
  else
94
92
  dep_version =~ word_dot_re
@@ -156,6 +156,7 @@ module LicenseFinder
156
156
 
157
157
  class PackageJson
158
158
  attr_reader :groups
159
+
159
160
  DEPENDENCY_GROUPS = %w[dependencies devDependencies].freeze
160
161
 
161
162
  def initialize(path)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class PubPackage < Package
5
+ def initialize(name, version, license_text, options = {})
6
+ super(name, version, options)
7
+ @license = License.find_by_text(license_text.to_s)
8
+ end
9
+
10
+ def licenses_from_spec
11
+ [@license].compact
12
+ end
13
+
14
+ def package_manager
15
+ 'Pub'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Printer
5
+ attr_reader :padding
6
+
7
+ def initialize #:nodoc:
8
+ @base = nil
9
+ @mute = false
10
+ @padding = 0
11
+ @always_force = false
12
+ end
13
+
14
+ def say(message = '', color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
15
+ buffer = prepare_message(message, *color)
16
+ buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
17
+
18
+ stdout.print(buffer)
19
+ stdout.flush
20
+ end
21
+
22
+ def prepare_message(message, *color)
23
+ spaces = ' ' * padding
24
+ spaces + set_color(message.to_s, *color)
25
+ end
26
+
27
+ def set_color(string, *) #:nodoc:
28
+ string
29
+ end
30
+
31
+ def padding=(value)
32
+ @padding = [0, value].max
33
+ end
34
+
35
+ def stdout
36
+ $stdout
37
+ end
38
+ end
39
+ end
@@ -9,11 +9,12 @@ module LicenseFinder
9
9
  def initialize(dependencies, options)
10
10
  @dependencies = dependencies
11
11
  @project_name = options[:project_name]
12
+ @use_spdx_id = options[:use_spdx_id]
12
13
  end
13
14
 
14
15
  private
15
16
 
16
- attr_reader :dependencies, :project_name
17
+ attr_reader :dependencies, :project_name, :use_spdx_id
17
18
 
18
19
  def sorted_dependencies
19
20
  dependencies.sort
@@ -60,7 +60,7 @@ module LicenseFinder
60
60
  if dep.missing?
61
61
  MISSING_DEPENDENCY_TEXT
62
62
  else
63
- dep.licenses.map(&:name).join(self.class::COMMA_SEP)
63
+ dep.licenses.map(&@use_spdx_id ? :standard_id : :name).join(self.class::COMMA_SEP)
64
64
  end
65
65
  end
66
66
 
@@ -5,7 +5,11 @@ module LicenseFinder
5
5
  TEMPLATE_PATH = ROOT_PATH.join('reports', 'templates')
6
6
 
7
7
  def to_s(filename = TEMPLATE_PATH.join("#{template_name}.erb"))
8
- template = ERB.new(filename.read, nil, '-')
8
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.6.0')
9
+ template = ERB.new(filename.read, nil, '-')
10
+ else
11
+ template = ERB.new(filename.read, trim_mode: '-')
12
+ end
9
13
  template.result(binding)
10
14
  end
11
15
 
@@ -22,7 +26,7 @@ module LicenseFinder
22
26
  end
23
27
 
24
28
  def link_to_license(license)
25
- link_to_maybe license.name, license.url
29
+ link_to_maybe (@use_spdx_id ? license.standard_id : license.name), license.url
26
30
  end
27
31
 
28
32
  def link_to_dependency(dependency)
@@ -42,7 +46,7 @@ module LicenseFinder
42
46
  end
43
47
 
44
48
  def license_names(dependency)
45
- dependency.licenses.map(&:name).sort.join ', '
49
+ dependency.licenses.map(&@use_spdx_id? :standard_id : :name).sort.join ', '
46
50
  end
47
51
 
48
52
  def license_links(dependency)
@@ -24,7 +24,8 @@ module LicenseFinder
24
24
  end
25
25
 
26
26
  def format_licenses(dep)
27
- dep.missing? ? [] : dep.licenses.map(&:name)
27
+ dep.missing? ? [] :
28
+ dep.licenses.map(&(@use_spdx_id ? :standard_id : :name))
28
29
  end
29
30
  end
30
31
  end
@@ -6,7 +6,11 @@ module LicenseFinder
6
6
  TEMPLATE_PATH = ROOT_PATH.join('templates')
7
7
 
8
8
  def to_s(filename = TEMPLATE_PATH.join("#{template_name}.erb"))
9
- template = ERB.new(filename.read, nil, '-')
9
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.6.0')
10
+ template = ERB.new(filename.read, nil, '-')
11
+ else
12
+ template = ERB.new(filename.read, trim_mode: '-')
13
+ end
10
14
  template.result(binding)
11
15
  end
12
16
 
@@ -6,7 +6,11 @@ module LicenseFinder
6
6
  TEMPLATE_PATH = ROOT_PATH.join('templates')
7
7
 
8
8
  def to_s(filename = TEMPLATE_PATH.join("#{template_name}.erb"))
9
- template = ERB.new(filename.read, nil, '-')
9
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.6.0')
10
+ template = ERB.new(filename.read, nil, '-')
11
+ else
12
+ template = ERB.new(filename.read, trim_mode: '-')
13
+ end
10
14
  template.result(binding)
11
15
  end
12
16
 
@@ -5,7 +5,7 @@ module LicenseFinder
5
5
  PACKAGE_MANAGERS = [
6
6
  GoModules, GoDep, GoWorkspace, Go15VendorExperiment, Glide, Gvt, Govendor, Trash, Dep, Bundler, NPM, Pip,
7
7
  Yarn, Bower, Maven, Gradle, CocoaPods, Rebar, Erlangmk, Nuget, Carthage, Mix, Conan, Sbt, Cargo, Dotnet, Composer, Pipenv,
8
- Conda, Spm
8
+ Conda, Spm, Pub
9
9
  ].freeze
10
10
 
11
11
  class << self
@@ -3,7 +3,7 @@
3
3
  version = File.read(File.expand_path('VERSION', __dir__)).strip
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.required_ruby_version = '>= 2.3.3'
6
+ s.required_ruby_version = '>= 2.4.0'
7
7
  s.name = 'license_finder'
8
8
  s.version = version
9
9
 
@@ -45,26 +45,28 @@ Gem::Specification.new do |s|
45
45
 
46
46
  s.add_dependency 'bundler'
47
47
  s.add_dependency 'rubyzip', '>=1', '<3'
48
- s.add_dependency 'thor', '~> 1.0.1'
48
+ s.add_dependency 'thor', '~> 1.2'
49
49
  s.add_dependency 'tomlrb', '>= 1.3', '< 2.1'
50
50
  s.add_dependency 'with_env', '1.1.0'
51
- s.add_dependency 'xml-simple', '~> 1.1.5'
51
+ s.add_dependency 'xml-simple', '~> 1.1.9'
52
52
 
53
53
  s.add_development_dependency 'addressable', '2.8.0'
54
- s.add_development_dependency 'capybara', '~> 3.15.0'
55
- s.add_development_dependency 'cocoapods', '>= 1.0.0' if RUBY_PLATFORM =~ /darwin/
56
- s.add_development_dependency 'fakefs', '~> 1.2.0'
57
- s.add_development_dependency 'mime-types', '3.3.1'
58
- s.add_development_dependency 'pry', '~> 0.14.0'
59
- s.add_development_dependency 'rake', '~> 13.0.1'
54
+ s.add_development_dependency 'capybara', '~> 3.32.2'
55
+ s.add_development_dependency 'cocoapods', '>= 1.0.0' if RUBY_PLATFORM.match?(/darwin/)
56
+ s.add_development_dependency 'e2mmap', '~> 0.1.0'
57
+ s.add_development_dependency 'fakefs', '~> 1.4.1'
58
+ s.add_development_dependency 'matrix', '~> 0.1.0'
59
+ s.add_development_dependency 'mime-types', '3.4.1'
60
+ s.add_development_dependency 'pry', '~> 0.14.1'
61
+ s.add_development_dependency 'rake', '~> 13.0.6'
60
62
  s.add_development_dependency 'rspec', '~> 3'
61
63
  s.add_development_dependency 'rspec-its', '~> 1.3.0'
62
- s.add_development_dependency 'rubocop', '~> 0.81.0'
63
- s.add_development_dependency 'rubocop-performance', '~> 1.5.0'
64
- s.add_development_dependency 'webmock', '~> 3.5'
64
+ s.add_development_dependency 'rubocop', '~> 1.12.1'
65
+ s.add_development_dependency 'rubocop-performance', '~> 1.10.2'
66
+ s.add_development_dependency 'webmock', '~> 3.14'
65
67
 
66
68
  s.add_development_dependency 'nokogiri', '~>1.10'
67
- s.add_development_dependency 'rack', '~> 2.2.2'
69
+ s.add_development_dependency 'rack', '~> 2.2.3'
68
70
  s.add_development_dependency 'rack-test', '~> 1.1.0', '> 0.7'
69
71
 
70
72
  s.files = `git ls-files`.split("\n").reject { |f| f.start_with?('spec', 'features') }