license_finder 6.14.1 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.rubocop.yml +12 -2
  4. data/CHANGELOG.md +45 -0
  5. data/Dockerfile +26 -5
  6. data/README.md +6 -6
  7. data/Rakefile +2 -2
  8. data/VERSION +1 -1
  9. data/bin/license_finder_pip.py +9 -7
  10. data/ci/pipelines/release.yml.erb +1 -1
  11. data/ci/scripts/pushscript.sh +2 -3
  12. data/ci/scripts/run-tests.sh +4 -3
  13. data/ci/tasks/rubocop.yml +1 -1
  14. data/dlf +9 -5
  15. data/lib/license_finder/cli/approvals.rb +2 -2
  16. data/lib/license_finder/cli/base.rb +9 -5
  17. data/lib/license_finder/cli/dependencies.rb +4 -4
  18. data/lib/license_finder/cli/ignored_dependencies.rb +3 -3
  19. data/lib/license_finder/cli/ignored_groups.rb +3 -3
  20. data/lib/license_finder/cli/inherited_decisions.rb +5 -5
  21. data/lib/license_finder/cli/licenses.rb +2 -2
  22. data/lib/license_finder/cli/main.rb +17 -11
  23. data/lib/license_finder/cli/permitted_licenses.rb +3 -3
  24. data/lib/license_finder/cli/project_name.rb +4 -4
  25. data/lib/license_finder/cli/restricted_licenses.rb +3 -3
  26. data/lib/license_finder/configuration.rb +6 -3
  27. data/lib/license_finder/core.rb +2 -1
  28. data/lib/license_finder/decisions.rb +9 -5
  29. data/lib/license_finder/license/definitions.rb +35 -1
  30. data/lib/license_finder/license/templates/Zlib.txt +17 -0
  31. data/lib/license_finder/license/text.rb +5 -3
  32. data/lib/license_finder/license.rb +8 -2
  33. data/lib/license_finder/logger.rb +1 -1
  34. data/lib/license_finder/package.rb +3 -11
  35. data/lib/license_finder/package_delta.rb +1 -1
  36. data/lib/license_finder/package_manager.rb +1 -0
  37. data/lib/license_finder/package_managers/cocoa_pods.rb +14 -7
  38. data/lib/license_finder/package_managers/conan.rb +2 -2
  39. data/lib/license_finder/package_managers/conda.rb +1 -1
  40. data/lib/license_finder/package_managers/glide.rb +7 -1
  41. data/lib/license_finder/package_managers/go_15vendorexperiment.rb +2 -2
  42. data/lib/license_finder/package_managers/go_dep.rb +1 -1
  43. data/lib/license_finder/package_managers/go_workspace.rb +1 -1
  44. data/lib/license_finder/package_managers/nuget.rb +1 -1
  45. data/lib/license_finder/package_managers/pub.rb +86 -0
  46. data/lib/license_finder/package_managers/sbt.rb +1 -5
  47. data/lib/license_finder/package_managers/yarn.rb +34 -6
  48. data/lib/license_finder/package_utils/license_files.rb +2 -2
  49. data/lib/license_finder/packages/bower_package.rb +5 -2
  50. data/lib/license_finder/packages/erlangmk_package.rb +2 -4
  51. data/lib/license_finder/packages/npm_package.rb +1 -0
  52. data/lib/license_finder/packages/pubspec_package.rb +18 -0
  53. data/lib/license_finder/printer.rb +39 -0
  54. data/lib/license_finder/report.rb +2 -1
  55. data/lib/license_finder/reports/csv_report.rb +1 -1
  56. data/lib/license_finder/reports/erb_report.rb +7 -3
  57. data/lib/license_finder/reports/json_report.rb +2 -1
  58. data/lib/license_finder/reports/junit_report.rb +5 -1
  59. data/lib/license_finder/reports/xml_report.rb +5 -1
  60. data/lib/license_finder/scanner.rb +1 -1
  61. data/license_finder.gemspec +16 -14
  62. metadata +61 -28
@@ -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 = {
@@ -9,12 +9,12 @@ module LicenseFinder
9
9
  end
10
10
 
11
11
  def current_packages
12
- cmd = "#{Yarn::SHELL_COMMAND}#{production_flag}"
12
+ cmd = "#{Yarn::SHELL_COMMAND}#{yarn1_production_flag}"
13
13
  suffix = " --cwd #{project_path}" unless project_path.nil?
14
14
  cmd += suffix unless suffix.nil?
15
15
 
16
- stdout, _stderr, status = Cmd.run(cmd)
17
- return [] unless status.success?
16
+ stdout, stderr, status = Cmd.run(cmd)
17
+ raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
18
18
 
19
19
  packages = []
20
20
  incompatible_packages = []
@@ -39,7 +39,7 @@ module LicenseFinder
39
39
  end
40
40
 
41
41
  def prepare
42
- prep_cmd = "#{prepare_command}#{production_flag}"
42
+ prep_cmd = prepare_command.to_s
43
43
  _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
44
44
  return if status.success?
45
45
 
@@ -56,11 +56,33 @@ module LicenseFinder
56
56
  end
57
57
 
58
58
  def prepare_command
59
- 'yarn install --ignore-engines --ignore-scripts'
59
+ if yarn2_project?
60
+ yarn2_prepare_command
61
+ else
62
+ yarn1_prepare_command
63
+ end
60
64
  end
61
65
 
62
66
  private
63
67
 
68
+ def yarn2_prepare_command
69
+ "#{yarn2_production_flag}yarn install"
70
+ end
71
+
72
+ def yarn1_prepare_command
73
+ "yarn install --ignore-engines --ignore-scripts#{yarn1_production_flag}"
74
+ end
75
+
76
+ def yarn2_project?
77
+ Dir.chdir(project_path) do
78
+ version_string, stderr_str, status = Cmd.run('yarn -v')
79
+ raise "Command 'yarn -v' failed to execute: #{stderr_str}" unless status.success?
80
+
81
+ version = version_string.split('.').map(&:to_i)
82
+ return version[0] >= 2
83
+ end
84
+ end
85
+
64
86
  def packages_from_json(json_data)
65
87
  body = json_data['body']
66
88
  head = json_data['head']
@@ -98,10 +120,16 @@ module LicenseFinder
98
120
  all_packages - [yarn_internal_package]
99
121
  end
100
122
 
101
- def production_flag
123
+ def yarn1_production_flag
102
124
  return '' if @ignored_groups.nil?
103
125
 
104
126
  @ignored_groups.include?('devDependencies') ? ' --production' : ''
105
127
  end
128
+
129
+ def yarn2_production_flag
130
+ return '' if @ignored_groups.nil?
131
+
132
+ @ignored_groups.include?('devDependencies') ? 'yarn plugin import workspace-tools && yarn workspaces focus --all --production && ' : ''
133
+ end
106
134
  end
107
135
  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
- s.add_development_dependency 'addressable', '2.7.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'
53
+ s.add_development_dependency 'addressable', '2.8.0'
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') }