licensee 9.11.0 → 9.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/bin/licensee +1 -0
  3. data/lib/licensee.rb +4 -2
  4. data/lib/licensee/commands/detect.rb +2 -0
  5. data/lib/licensee/commands/diff.rb +5 -1
  6. data/lib/licensee/commands/license_path.rb +2 -0
  7. data/lib/licensee/commands/version.rb +2 -0
  8. data/lib/licensee/content_helper.rb +20 -10
  9. data/lib/licensee/hash_helper.rb +2 -0
  10. data/lib/licensee/license.rb +2 -0
  11. data/lib/licensee/license_field.rb +2 -0
  12. data/lib/licensee/license_meta.rb +2 -0
  13. data/lib/licensee/license_rules.rb +2 -0
  14. data/lib/licensee/matchers.rb +2 -0
  15. data/lib/licensee/matchers/cabal.rb +15 -1
  16. data/lib/licensee/matchers/cargo.rb +2 -0
  17. data/lib/licensee/matchers/copyright.rb +2 -0
  18. data/lib/licensee/matchers/cran.rb +2 -0
  19. data/lib/licensee/matchers/dice.rb +3 -1
  20. data/lib/licensee/matchers/dist_zilla.rb +2 -0
  21. data/lib/licensee/matchers/exact.rb +2 -0
  22. data/lib/licensee/matchers/gemspec.rb +2 -0
  23. data/lib/licensee/matchers/matcher.rb +2 -0
  24. data/lib/licensee/matchers/npm_bower.rb +2 -0
  25. data/lib/licensee/matchers/package.rb +2 -0
  26. data/lib/licensee/matchers/reference.rb +2 -0
  27. data/lib/licensee/matchers/spdx.rb +2 -0
  28. data/lib/licensee/project_files.rb +2 -0
  29. data/lib/licensee/project_files/license_file.rb +5 -3
  30. data/lib/licensee/project_files/package_manager_file.rb +2 -0
  31. data/lib/licensee/project_files/project_file.rb +11 -4
  32. data/lib/licensee/project_files/readme_file.rb +2 -0
  33. data/lib/licensee/projects.rb +2 -0
  34. data/lib/licensee/projects/fs_project.rb +2 -0
  35. data/lib/licensee/projects/git_project.rb +16 -8
  36. data/lib/licensee/projects/github_project.rb +2 -0
  37. data/lib/licensee/projects/project.rb +4 -2
  38. data/lib/licensee/rule.rb +2 -0
  39. data/lib/licensee/version.rb +3 -1
  40. data/spec/bin_spec.rb +2 -0
  41. data/spec/fixture_spec.rb +46 -0
  42. data/spec/fixtures/detect.json +6 -4
  43. data/spec/fixtures/fixtures.yml +110 -0
  44. data/spec/fixtures/html/license.html +262 -0
  45. data/spec/fixtures/license-hashes.json +30 -27
  46. data/spec/fixtures/mit-optional/LICENSE.txt +21 -0
  47. data/spec/integration_spec.rb +20 -0
  48. data/spec/licensee/commands/detect_spec.rb +5 -1
  49. data/spec/licensee/commands/license_path_spec.rb +2 -0
  50. data/spec/licensee/commands/version_spec.rb +2 -0
  51. data/spec/licensee/content_helper_spec.rb +22 -5
  52. data/spec/licensee/hash_helper_spec.rb +2 -0
  53. data/spec/licensee/license_field_spec.rb +2 -0
  54. data/spec/licensee/license_meta_spec.rb +2 -0
  55. data/spec/licensee/license_rules_spec.rb +2 -0
  56. data/spec/licensee/license_spec.rb +4 -2
  57. data/spec/licensee/matchers/cabal_matcher_spec.rb +93 -0
  58. data/spec/licensee/matchers/cargo_matcher_spec.rb +2 -0
  59. data/spec/licensee/matchers/copyright_matcher_spec.rb +4 -2
  60. data/spec/licensee/matchers/cran_matcher_spec.rb +2 -0
  61. data/spec/licensee/matchers/dice_matcher_spec.rb +2 -0
  62. data/spec/licensee/matchers/dist_zilla_matcher_spec.rb +2 -0
  63. data/spec/licensee/matchers/exact_matcher_spec.rb +2 -0
  64. data/spec/licensee/matchers/gemspec_matcher_spec.rb +2 -0
  65. data/spec/licensee/matchers/matcher_spec.rb +2 -0
  66. data/spec/licensee/matchers/npm_bower_matcher_spec.rb +2 -0
  67. data/spec/licensee/matchers/package_matcher_spec.rb +2 -0
  68. data/spec/licensee/matchers/reference_matcher_spec.rb +2 -0
  69. data/spec/licensee/matchers/spdx_matcher_spec.rb +2 -0
  70. data/spec/licensee/project_files/license_file_spec.rb +3 -1
  71. data/spec/licensee/project_files/package_info_spec.rb +2 -0
  72. data/spec/licensee/project_files/project_file_spec.rb +3 -0
  73. data/spec/licensee/project_files/readme_file_spec.rb +2 -0
  74. data/spec/licensee/project_spec.rb +2 -0
  75. data/spec/licensee/projects/git_project_spec.rb +23 -0
  76. data/spec/licensee/projects/github_project_spec.rb +2 -0
  77. data/spec/licensee/rule_spec.rb +2 -0
  78. data/spec/licensee_spec.rb +3 -1
  79. data/spec/spec_helper.rb +16 -3
  80. data/spec/vendored_license_spec.rb +9 -7
  81. data/vendor/choosealicense.com/_licenses/0bsd.txt +39 -0
  82. data/vendor/choosealicense.com/_licenses/afl-3.0.txt +7 -5
  83. data/vendor/choosealicense.com/_licenses/bsd-3-clause-clear.txt +1 -1
  84. data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +1 -1
  85. data/vendor/choosealicense.com/_licenses/cecill-2.1.txt +579 -0
  86. data/vendor/choosealicense.com/_licenses/epl-1.0.txt +1 -1
  87. data/vendor/choosealicense.com/_licenses/epl-2.0.txt +1 -1
  88. data/vendor/choosealicense.com/_licenses/odbl-1.0.txt +573 -0
  89. data/vendor/choosealicense.com/_licenses/osl-3.0.txt +1 -1
  90. data/vendor/choosealicense.com/_licenses/unlicense.txt +1 -1
  91. data/vendor/choosealicense.com/_licenses/upl-1.0.txt +3 -3
  92. metadata +40 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 613429f0350489c8dbdbdc80973d2557ad655efd2b89786096f290cf52632344
4
- data.tar.gz: 87fca6ceddb6972dd946720355e6efb2661793d671ff92ce8934e281affa6ad5
3
+ metadata.gz: d7dc009b0467cfb305e8dac051ed4e78d2f35d0454f2e14cef0952338540f8ae
4
+ data.tar.gz: 3c27bb3dd3cea6d62fab826b81fab93d9152893851b541c91d69406cdf9fcbd8
5
5
  SHA512:
6
- metadata.gz: 7bcb1c30bdebf4cad0a84ef7fd9dd4afe922ba8acac1a9124bdd96dc64d4ef736787f1b70c4ab0d01c3c05ba3547300caa3c882b2d99ea15117f72335f56b0a5
7
- data.tar.gz: bb2f30c4f70a4610f55a530c36b65852270558b8b36342b1fe8ad1113afa4dca711214545b3abbeb19cdba8d7e2d05643b0e138c8964a5b3f51106ce8c1bf3db
6
+ metadata.gz: 07f19b33f70b0b73611d34e474f2aa4e4d7f62c7451cdf70f76774beceac2c75ab3d1cc5048061a848b979a54032aad6dd1ba278c79cd798029efd6873d54425
7
+ data.tar.gz: 96c5e66f65307e7feb2c00b3f06661b093c60995d049f7fd19cc27b76881965a1d33768a16b0a3a3b085e9392ef828dce9cf692ee04255dd9ea2c6d22da38da6
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'dotenv/load'
4
5
  require 'thor'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'licensee/version'
2
4
  require 'forwardable'
3
5
  require 'pathname'
@@ -19,7 +21,7 @@ module Licensee
19
21
  CONFIDENCE_THRESHOLD = 98
20
22
 
21
23
  # Base domain from which to build license URLs
22
- DOMAIN = 'http://choosealicense.com'.freeze
24
+ DOMAIN = 'http://choosealicense.com'
23
25
 
24
26
  class << self
25
27
  attr_writer :confidence_threshold
@@ -49,7 +51,7 @@ module Licensee
49
51
  end
50
52
 
51
53
  # Inverse of the confidence threshold, represented as a float
52
- # By default this will be 0.05
54
+ # By default this will be 0.02
53
55
  def inverse_confidence_threshold
54
56
  @inverse_confidence_threshold ||=
55
57
  (1 - Licensee.confidence_threshold / 100.0).round(2)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class LicenseeCLI < Thor
2
4
  # Methods to call when displaying information about ProjectFiles
3
5
  MATCHED_FILE_METHODS = %i[
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tmpdir'
2
4
 
3
5
  class LicenseeCLI < Thor
@@ -47,7 +49,9 @@ class LicenseeCLI < Thor
47
49
  end
48
50
 
49
51
  def expected_license
50
- @expected_license ||= Licensee::License.find options[:license] if options[:license]
52
+ if options[:license]
53
+ @expected_license ||= Licensee::License.find options[:license]
54
+ end
51
55
  return @expected_license if @expected_license
52
56
 
53
57
  if options[:license]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class LicenseeCLI < Thor
2
4
  desc 'license-path [PATH]', "Returns the path to the given project's license file"
3
5
  def license_path(_path)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class LicenseeCLI < Thor
2
4
  desc 'version', 'Return the Licensee version'
3
5
  def version
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
  require 'digest'
3
5
 
@@ -22,7 +24,8 @@ module Licensee
22
24
  bullet: /\n\n\s*(?:[*-]|\(?[\da-z]{1,2}[)\.])\s+/i,
23
25
  developed_by: /#{START_REGEX}developed by:.*?\n\n/im,
24
26
  quote_begin: /[`'"‘“]/,
25
- quote_end: /[`'"’”]/
27
+ quote_end: /[`'"’”]/,
28
+ mit_optional: /\(including the next paragraph\)/i
26
29
  }.freeze
27
30
  NORMALIZATIONS = {
28
31
  lists: { from: /^\s*(?:\d\.|\*)\s+([^\n])/, to: '- \1' },
@@ -85,13 +88,12 @@ module Licensee
85
88
  hrs markdown_headings borders title version url copyright
86
89
  block_markup span_markup link_markup
87
90
  all_rights_reserved developed_by end_of_terms whitespace
91
+ mit_optional
88
92
  ].freeze
89
93
 
90
94
  # A set of each word in the license, without duplicates
91
95
  def wordset
92
- @wordset ||= if content_normalized
93
- content_normalized.scan(/(?:\w(?:'s|(?<=s)')?)+/).to_set
94
- end
96
+ @wordset ||= content_normalized&.scan(/(?:\w(?:'s|(?<=s)')?)+/)&.to_set
95
97
  end
96
98
 
97
99
  # Number of characteres in the normalized content
@@ -115,8 +117,10 @@ module Licensee
115
117
  # Given another license or project file, calculates the similarity
116
118
  # as a percentage of words in common
117
119
  def similarity(other)
118
- overlap = (wordset & other.wordset).size
119
- total = wordset.size + other.wordset.size
120
+ wordset_fieldless = wordset - LicenseField.keys
121
+ fields_removed = wordset.size - wordset_fieldless.size
122
+ overlap = (wordset_fieldless & other.wordset).size
123
+ total = wordset_fieldless.size + other.wordset.size - fields_removed
120
124
  100.0 * (overlap * 2.0 / total)
121
125
  end
122
126
 
@@ -132,7 +136,7 @@ module Licensee
132
136
  def content_without_title_and_version
133
137
  @content_without_title_and_version ||= begin
134
138
  @_content = nil
135
- ops = %i[hrs comments markdown_headings title version]
139
+ ops = %i[html hrs comments markdown_headings title version]
136
140
  ops.each { |op| strip(op) }
137
141
  _content
138
142
  end
@@ -183,7 +187,7 @@ module Licensee
183
187
  end
184
188
 
185
189
  def self.format_percent(float)
186
- "#{format('%.2f', float)}%"
190
+ "#{format('%<float>.2f', float: float)}%"
187
191
  end
188
192
 
189
193
  def self.title_regex
@@ -206,11 +210,9 @@ module Licensee
206
210
 
207
211
  private
208
212
 
209
- # rubocop:disable Naming/MemoizedInstanceVariableName
210
213
  def _content
211
214
  @_content ||= content.to_s.dup.strip
212
215
  end
213
- # rubocop:enable Naming/MemoizedInstanceVariableName
214
216
 
215
217
  def strip(regex_or_sym)
216
218
  return unless _content
@@ -265,6 +267,14 @@ module Licensee
265
267
  normalize(REGEXES[:link_markup], '\1')
266
268
  end
267
269
 
270
+ def strip_html
271
+ return unless respond_to?(:filename) && filename
272
+ return unless File.extname(filename) =~ /\.html?/i
273
+
274
+ require 'reverse_markdown'
275
+ @_content = ReverseMarkdown.convert(_content, unknown_tags: :bypass)
276
+ end
277
+
268
278
  def normalize(from_or_key, to = nil)
269
279
  operation = { from: from_or_key, to: to } if to
270
280
  operation ||= NORMALIZATIONS[from_or_key]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module HashHelper
3
5
  def to_h
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Licensee
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  class LicenseField < Struct.new(:name, :description)
3
5
  class << self
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  class LicenseMeta < Struct.new(
3
5
  :title, :spdx_id, :source, :description, :how, :conditions, :permissions,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  # Exposes #conditions, #permissions, and #limitation arrays of LicenseRules
3
5
  class LicenseRules < Struct.new(:conditions, :permissions, :limitations)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  autoload :Matcher, 'licensee/matchers/matcher'
@@ -1,15 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Cabal < Licensee::Matchers::Package
4
6
  # While we could parse the cabal file, prefer
5
7
  # a lenient regex for speed and security. Moar parsing moar problems.
6
8
  LICENSE_REGEX = /^\s*license\s*\:\s*([a-z\-0-9\.]+)\s*$/ix.freeze
9
+ LICENSE_CONVERSIONS = {
10
+ 'GPL-2' => 'GPL-2.0',
11
+ 'GPL-3' => 'GPL-3.0',
12
+ 'LGPL-3' => 'LGPL-3.0',
13
+ 'AGPL-3' => 'AGPL-3.0',
14
+ 'BSD2' => 'BSD-2-Clause',
15
+ 'BSD3' => 'BSD-3-Clause'
16
+ }.freeze
7
17
 
8
18
  private
9
19
 
10
20
  def license_property
11
21
  match = @file.content.match LICENSE_REGEX
12
- match[1].downcase if match && match[1]
22
+ spdx_name(match[1]).downcase if match && match[1]
23
+ end
24
+
25
+ def spdx_name(cabal_name)
26
+ LICENSE_CONVERSIONS[cabal_name] || cabal_name
13
27
  end
14
28
  end
15
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Cargo < Licensee::Matchers::Package
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Copyright < Licensee::Matchers::Matcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Cran < Licensee::Matchers::Package
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Dice < Licensee::Matchers::Matcher
@@ -49,7 +51,7 @@ module Licensee
49
51
 
50
52
  # Confidence that the matched license is a match
51
53
  def confidence
52
- @confidence ||= match ? file.similarity(match) : 0
54
+ @confidence ||= match ? match.similarity(file) : 0
53
55
  end
54
56
 
55
57
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class DistZilla < Licensee::Matchers::Package
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Exact < Licensee::Matchers::Matcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Gemspec < Licensee::Matchers::Package
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Matcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class NpmBower < Licensee::Matchers::Package
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Package < Licensee::Matchers::Matcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  # Matches README files that include a license by reference
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Matchers
3
5
  class Spdx < Licensee::Matchers::Package
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module ProjectFiles
3
5
  autoload :ProjectFile, 'licensee/project_files/project_file'
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module ProjectFiles
3
5
  class LicenseFile < Licensee::ProjectFiles::ProjectFile
4
6
  include Licensee::ContentHelper
5
7
 
6
8
  # List of extensions to give preference to
7
- PREFERRED_EXT = %w[md markdown txt].freeze
9
+ PREFERRED_EXT = %w[md markdown txt html].freeze
8
10
  PREFERRED_EXT_REGEX = /\.#{Regexp.union(PREFERRED_EXT)}\z/.freeze
9
11
 
10
12
  # Regex to match any extension except .spdx or .header
@@ -72,11 +74,11 @@ module Licensee
72
74
  end
73
75
 
74
76
  def gpl?
75
- license && license.gpl?
77
+ license&.gpl?
76
78
  end
77
79
 
78
80
  def license
79
- if matcher && matcher.match
81
+ if matcher&.match
80
82
  matcher.match
81
83
  else
82
84
  License.find('other')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module ProjectFiles
3
5
  class PackageManagerFile < Licensee::ProjectFiles::ProjectFile
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A project file is a file within a project that contains license information
2
4
  # Currently extended by LicenseFile, PackageManagerFile, and ReadmeFile
3
5
  #
@@ -13,6 +15,7 @@ module Licensee
13
15
  include Licensee::HashHelper
14
16
  HASH_METHODS = %i[
15
17
  filename content content_hash content_normalized matcher matched_license
18
+ attribution
16
19
  ].freeze
17
20
 
18
21
  ENCODING = Encoding::UTF_8
@@ -32,7 +35,7 @@ module Licensee
32
35
  #
33
36
  # Returns a new Licensee::ProjectFile
34
37
  def initialize(content, metadata = {})
35
- @content = content
38
+ @content = content.dup
36
39
  @content.force_encoding(ENCODING)
37
40
  unless @content.valid_encoding?
38
41
  @content.encode!(ENCODING, ENCODING_OPTIONS)
@@ -70,17 +73,17 @@ module Licensee
70
73
 
71
74
  # Returns the percent confident with the match
72
75
  def confidence
73
- matcher && matcher.confidence
76
+ matcher&.confidence
74
77
  end
75
78
 
76
79
  def license
77
- matcher && matcher.match
80
+ matcher&.match
78
81
  end
79
82
 
80
83
  alias match license
81
84
 
82
85
  def matched_license
83
- license.spdx_id if license
86
+ license&.spdx_id
84
87
  end
85
88
 
86
89
  # Is this file a COPYRIGHT file with only a copyright statement?
@@ -99,6 +102,10 @@ module Licensee
99
102
  def content_normalized
100
103
  nil
101
104
  end
105
+
106
+ def attribution
107
+ nil
108
+ end
102
109
  end
103
110
  end
104
111
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module ProjectFiles
3
5
  class ReadmeFile < Licensee::ProjectFiles::LicenseFile
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Licensee
2
4
  module Projects
3
5
  autoload :Project, 'licensee/projects/project'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Filesystem-based project
2
4
  #
3
5
  # Analyze a folder on the filesystem for license information