licensee 4.9.0 → 5.0.0b1
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.
- checksums.yaml +4 -4
- data/bin/licensee +3 -2
- data/lib/licensee.rb +20 -5
- data/lib/licensee/license.rb +25 -5
- data/lib/licensee/matcher.rb +4 -0
- data/lib/licensee/matchers/copyright_matcher.rb +1 -1
- data/lib/licensee/matchers/gemspec_matcher.rb +16 -0
- data/lib/licensee/matchers/npm_bower_matcher.rb +15 -0
- data/lib/licensee/matchers/package_matcher.rb +16 -0
- data/lib/licensee/project.rb +18 -40
- data/lib/licensee/project_file.rb +91 -0
- data/lib/licensee/version.rb +1 -1
- data/test/fixtures/bower/bower.json +3 -0
- data/test/fixtures/npm-non-spdx/package.json +3 -0
- data/test/fixtures/npm/package.json +3 -0
- data/test/functions.rb +2 -2
- data/test/helper.rb +1 -4
- data/test/test_licensee.rb +20 -6
- data/test/test_licensee_bin.rb +1 -1
- data/test/test_licensee_copyright_matcher.rb +7 -7
- data/test/test_licensee_exact_matcher.rb +2 -2
- data/test/test_licensee_gemspec_matcher.rb +19 -0
- data/test/test_licensee_git_matcher.rb +2 -2
- data/test/test_licensee_levenshtein_matcher.rb +4 -4
- data/test/test_licensee_license.rb +19 -0
- data/test/test_licensee_npm_bower_matcher.rb +33 -0
- data/test/test_licensee_project.rb +16 -40
- data/test/test_licensee_project_file.rb +59 -0
- data/test/test_licensee_vendor.rb +1 -1
- metadata +14 -8
- data/lib/licensee/license_file.rb +0 -52
- data/lib/licensee/licenses.rb +0 -36
- data/test/test_licensee_license_file.rb +0 -33
- data/test/test_licensee_licenses.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49baf7865bddf84e8237149cba6f21768e661c39
|
4
|
+
data.tar.gz: 95dbc39d96bed4d0952df9e85eb56ae37f387c1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60a4c027e6d388d732ad3588606c380d90595be0955f55e9415a727370c78c8faff40c781843bc04989fb3a591821f91579079f54c2197f02778e9cac6cb73a3
|
7
|
+
data.tar.gz: 510467b863f02cdb658986dd5626460d0383c5602d22c3f170094d7d38bf80e56727691a4c8fc30dc7b4c79003a610383a90dfa4864fc87b1f3a4f83eb404012
|
data/bin/licensee
CHANGED
@@ -3,11 +3,12 @@ require_relative "../lib/licensee"
|
|
3
3
|
|
4
4
|
path = ARGV[0] || Dir.pwd
|
5
5
|
|
6
|
+
Licensee.package_manager_files = true
|
6
7
|
project = Licensee::Project.new(path)
|
7
|
-
license = project.
|
8
|
+
license = project.matched_file
|
8
9
|
|
9
10
|
if license
|
10
|
-
puts "
|
11
|
+
puts "Matched file: #{license.path}"
|
11
12
|
puts "License: #{license.match ? license.match.meta['title'] : 'no license'}"
|
12
13
|
puts "Confidence: #{license.confidence}%"
|
13
14
|
puts "Method: #{license.matcher.class}"
|
data/lib/licensee.rb
CHANGED
@@ -5,15 +5,17 @@ require 'levenshtein'
|
|
5
5
|
|
6
6
|
require_relative "licensee/version"
|
7
7
|
require_relative "licensee/license"
|
8
|
-
require_relative "licensee/licenses"
|
9
|
-
require_relative "licensee/license_file"
|
10
8
|
require_relative "licensee/project"
|
9
|
+
require_relative "licensee/project_file"
|
11
10
|
require_relative "licensee/filesystem_repository"
|
12
11
|
require_relative "licensee/matcher"
|
13
12
|
require_relative "licensee/matchers/exact_matcher"
|
14
13
|
require_relative "licensee/matchers/copyright_matcher"
|
15
14
|
require_relative "licensee/matchers/git_matcher"
|
16
15
|
require_relative "licensee/matchers/levenshtein_matcher"
|
16
|
+
require_relative "licensee/matchers/package_matcher"
|
17
|
+
require_relative "licensee/matchers/gemspec_matcher"
|
18
|
+
require_relative "licensee/matchers/npm_bower_matcher"
|
17
19
|
|
18
20
|
class Licensee
|
19
21
|
|
@@ -25,11 +27,11 @@ class Licensee
|
|
25
27
|
|
26
28
|
class << self
|
27
29
|
|
28
|
-
attr_writer :confidence_threshold
|
30
|
+
attr_writer :confidence_threshold, :package_manager_files
|
29
31
|
|
30
32
|
# Returns an array of Licensee::License instances
|
31
33
|
def licenses
|
32
|
-
@licenses ||= Licensee::
|
34
|
+
@licenses ||= Licensee::License.all
|
33
35
|
end
|
34
36
|
|
35
37
|
# Returns the license for a given git repo
|
@@ -45,11 +47,24 @@ class Licensee
|
|
45
47
|
# Array of matchers to use, in order of preference
|
46
48
|
# The order should be decending order of anticipated speed to match
|
47
49
|
def matchers
|
48
|
-
|
50
|
+
matchers = [
|
51
|
+
Licensee::CopyrightMatcher,
|
52
|
+
Licensee::ExactMatcher,
|
53
|
+
Licensee::GitMatcher,
|
54
|
+
Licensee::LevenshteinMatcher,
|
55
|
+
Licensee::GemspecMatcher,
|
56
|
+
Licensee::NpmBowerMatcher
|
57
|
+
]
|
58
|
+
matchers.reject! { |m| m.package_manager? } unless package_manager_files?
|
59
|
+
matchers
|
49
60
|
end
|
50
61
|
|
51
62
|
def confidence_threshold
|
52
63
|
@confidence_threshold ||= CONFIDENCE_THRESHOLD
|
53
64
|
end
|
65
|
+
|
66
|
+
def package_manager_files?
|
67
|
+
@package_manager_files ||= false
|
68
|
+
end
|
54
69
|
end
|
55
70
|
end
|
data/lib/licensee/license.rb
CHANGED
@@ -2,16 +2,36 @@ class Licensee
|
|
2
2
|
class InvalidLicense < ArgumentError; end
|
3
3
|
class License
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
class << self
|
6
|
+
def all
|
7
|
+
@all ||= keys.map { |key| self.new(key) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def keys
|
11
|
+
@keys ||= license_files.map { |l| File.basename(l, ".txt").downcase }
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(key)
|
15
|
+
key = key.downcase
|
16
|
+
all.find { |l| l.key == key }
|
17
|
+
end
|
18
|
+
alias_method :[], :find
|
19
|
+
|
20
|
+
def license_dir
|
21
|
+
File.expand_path "../../vendor/choosealicense.com/_licenses", File.dirname(__FILE__)
|
22
|
+
end
|
23
|
+
|
24
|
+
def license_files
|
25
|
+
@license_files ||= Dir.glob("#{license_dir}/*.txt")
|
26
|
+
end
|
7
27
|
end
|
8
28
|
|
9
29
|
attr_reader :key
|
10
30
|
|
11
31
|
YAML_DEFAULTS = {
|
12
32
|
"featured" => false,
|
13
|
-
"hidden"
|
14
|
-
"variant"
|
33
|
+
"hidden" => false,
|
34
|
+
"variant" => false
|
15
35
|
}
|
16
36
|
|
17
37
|
HIDDEN_LICENSES = %w[other no-license]
|
@@ -22,7 +42,7 @@ class Licensee
|
|
22
42
|
|
23
43
|
# Path to vendored license file on disk
|
24
44
|
def path
|
25
|
-
@path ||= File.expand_path "#{@key}.txt", Licensee::
|
45
|
+
@path ||= File.expand_path "#{@key}.txt", Licensee::License.license_dir
|
26
46
|
end
|
27
47
|
|
28
48
|
# Raw content of license file, including YAML front matter
|
data/lib/licensee/matcher.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Licensee
|
2
|
+
class GemspecMatcher < PackageMatcher
|
3
|
+
|
4
|
+
# We definitely don't want to be evaling arbitrary Gemspec files
|
5
|
+
# While not 100% accurate, use some lenient regex to try to grep the
|
6
|
+
# license declaration from the Gemspec as a string, if any
|
7
|
+
LICENSE_REGEX = /^\s*[a-z0-9_]+\.license\s*\=\s*[\'\"]([a-z\-0-9\.]+)[\'\"]\s*$/i
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def license_property
|
12
|
+
match = file.content.match LICENSE_REGEX
|
13
|
+
match[1].downcase if match && match[1]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Licensee
|
2
|
+
class NpmBowerMatcher < PackageMatcher
|
3
|
+
|
4
|
+
# While we could parse the package.json or bower.json file, prefer
|
5
|
+
# a lenient regex for speed and security. Moar parsing moar problems.
|
6
|
+
LICENSE_REGEX = /\s*[\"\']license[\"\']\s*\:\s*[\'\"]([a-z\-0-9\.]+)[\'\"],?\s*/i
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def license_property
|
11
|
+
match = file.content.match LICENSE_REGEX
|
12
|
+
match[1].downcase if match && match[1]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/licensee/project.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Licensee
|
2
2
|
class Project
|
3
|
-
attr_reader :repository
|
3
|
+
attr_reader :repository, :revision
|
4
4
|
|
5
5
|
# Initializes a new project
|
6
6
|
#
|
@@ -13,66 +13,44 @@ class Licensee
|
|
13
13
|
begin
|
14
14
|
@repository = Rugged::Repository.new(path_or_repo)
|
15
15
|
rescue Rugged::RepositoryError
|
16
|
-
if revision
|
17
|
-
|
18
|
-
else
|
19
|
-
@repository = FilesystemRepository.new(path_or_repo)
|
20
|
-
end
|
16
|
+
raise if revision
|
17
|
+
@repository = FilesystemRepository.new(path_or_repo)
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
21
|
@revision = revision
|
25
22
|
end
|
26
23
|
|
27
|
-
# Returns
|
24
|
+
# Returns the matching Licensee::License instance if a license can be detected
|
25
|
+
def license
|
26
|
+
@license ||= matched_file.match if matched_file
|
27
|
+
end
|
28
|
+
|
28
29
|
def license_file
|
29
|
-
@license_file ||=
|
30
|
+
@license_file ||= files.select { |f| f.license? }.sort_by { |f| f.license_score }.last
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
@
|
33
|
+
def package_file
|
34
|
+
return unless Licensee.package_manager_files?
|
35
|
+
@package_file ||= files.select { |f| f.package? }.sort_by { |f| f.package_score }.last
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
# filename - (string) the name of the file to score
|
40
|
-
#
|
41
|
-
# Returns 1.0 if the file is definitely a license file
|
42
|
-
# Returns 0.75 if the file is probably a license file
|
43
|
-
# Returns 0.5 if the file is likely a license file
|
44
|
-
# Returns 0.0 if the file is definitely not a license file
|
45
|
-
def self.match_license_file(filename)
|
46
|
-
return 1.0 if filename =~ /\A(un)?licen[sc]e(\.[^.]+)?\z/i
|
47
|
-
return 0.75 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
|
48
|
-
return 0.5 if filename =~ /licen[sc]e/i
|
49
|
-
return 0.0
|
38
|
+
def matched_file
|
39
|
+
license_file || package_file
|
50
40
|
end
|
51
41
|
|
52
42
|
private
|
53
43
|
|
54
44
|
def commit
|
55
|
-
@revision ?
|
45
|
+
@commit ||= revision ? repository.lookup(revision) : repository.last_commit
|
56
46
|
end
|
57
47
|
|
58
48
|
def tree
|
59
|
-
commit.tree.select { |blob| blob[:type] == :blob }
|
60
|
-
end
|
61
|
-
|
62
|
-
# Detects the license file, if any
|
63
|
-
# Returns the blob hash as detected in the tree
|
64
|
-
def license_hash
|
65
|
-
hashes = tree.map { |blob| [self.class.match_license_file(blob[:name]), blob] }
|
66
|
-
hash = hashes.select { |hash| hash[0] > 0 }.sort_by { |hash| hash[0] }.last
|
67
|
-
hash[1] if hash
|
68
|
-
end
|
69
|
-
|
70
|
-
def license_blob
|
71
|
-
@repository.lookup(license_hash[:oid]) if license_hash
|
49
|
+
@tree ||= commit.tree.select { |blob| blob[:type] == :blob }
|
72
50
|
end
|
73
51
|
|
74
|
-
def
|
75
|
-
|
52
|
+
def files
|
53
|
+
@files ||= tree.map { |blob| ProjectFile.new(repository.lookup(blob[:oid]), blob[:name]) }
|
76
54
|
end
|
77
55
|
end
|
78
56
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class Licensee
|
2
|
+
class ProjectFile
|
3
|
+
|
4
|
+
# Note: File can be a license file (e.g., `LICENSE.txt`)
|
5
|
+
# or a package manager file (e.g, `package.json`)
|
6
|
+
|
7
|
+
attr_reader :blob, :path
|
8
|
+
alias_method :filename, :path
|
9
|
+
|
10
|
+
def initialize(blob, path)
|
11
|
+
@blob = blob
|
12
|
+
@path = path
|
13
|
+
end
|
14
|
+
|
15
|
+
# Raw file contents
|
16
|
+
def content
|
17
|
+
@contents ||= blob.content.force_encoding("UTF-8")
|
18
|
+
end
|
19
|
+
alias_method :to_s, :content
|
20
|
+
alias_method :contents, :content
|
21
|
+
|
22
|
+
# File content with all whitespace replaced with a single space
|
23
|
+
def content_normalized
|
24
|
+
@content_normalized ||= content.downcase.gsub(/\s+/, " ").strip
|
25
|
+
end
|
26
|
+
|
27
|
+
# Determines which matching strategy to use, returns an instane of that matcher
|
28
|
+
def matcher
|
29
|
+
@matcher ||= Licensee.matchers.map { |m| m.new(self) }.find { |m| m.match }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns an Licensee::License instance of the matches license
|
33
|
+
def match
|
34
|
+
@match ||= matcher.match if matcher
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the percent confident with the match
|
38
|
+
def confidence
|
39
|
+
@condience ||= matcher.confidence if matcher
|
40
|
+
end
|
41
|
+
|
42
|
+
def similarity(other)
|
43
|
+
blob.hashsig(Rugged::Blob::HashSignature::WHITESPACE_SMART)
|
44
|
+
other.hashsig ? blob.similarity(other.hashsig) : 0
|
45
|
+
rescue Rugged::InvalidError
|
46
|
+
0
|
47
|
+
end
|
48
|
+
|
49
|
+
# Comptutes a diff between known license and project license
|
50
|
+
def diff(options={})
|
51
|
+
options = options.merge(:reverse => true)
|
52
|
+
blob.diff(match.body, options).to_s if match
|
53
|
+
end
|
54
|
+
|
55
|
+
def license_score
|
56
|
+
self.class.license_score(filename)
|
57
|
+
end
|
58
|
+
|
59
|
+
def license?
|
60
|
+
license_score != 0.0
|
61
|
+
end
|
62
|
+
|
63
|
+
def package_score
|
64
|
+
return 1.0 if filename =~ /[a-zA-Z0-9\-_]+\.gemspec/
|
65
|
+
return 1.0 if filename =~ /package\.json/
|
66
|
+
return 0.75 if filename =~ /bower.json/
|
67
|
+
return 0.0
|
68
|
+
end
|
69
|
+
|
70
|
+
def package?
|
71
|
+
Licensee.package_manager_files? && package_score != 0.0
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
# Scores a given file as a potential license
|
76
|
+
#
|
77
|
+
# filename - (string) the name of the file to score
|
78
|
+
#
|
79
|
+
# Returns 1.0 if the file is definitely a license file
|
80
|
+
# Returns 0.75 if the file is probably a license file
|
81
|
+
# Returns 0.5 if the file is likely a license file
|
82
|
+
# Returns 0.0 if the file is definitely not a license file
|
83
|
+
def license_score(filename)
|
84
|
+
return 1.0 if filename =~ /\A(un)?licen[sc]e(\.[^.]+)?\z/i
|
85
|
+
return 0.75 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
|
86
|
+
return 0.5 if filename =~ /licen[sc]e/i
|
87
|
+
return 0.0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/licensee/version.rb
CHANGED
data/test/functions.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Pulled from helper.rb because something in the test suite monkey patches benchmarking
|
2
2
|
|
3
3
|
require 'securerandom'
|
4
|
-
|
4
|
+
require_relative '../lib/licensee'
|
5
5
|
|
6
6
|
def fixtures_base
|
7
7
|
File.expand_path "fixtures", File.dirname( __FILE__ )
|
@@ -36,7 +36,7 @@ def verify_license_file(license, chaos = false, wrap=false)
|
|
36
36
|
text = wrap(text, wrap) if wrap
|
37
37
|
|
38
38
|
blob = FakeBlob.new(text)
|
39
|
-
license_file = Licensee::
|
39
|
+
license_file = Licensee::ProjectFile.new(blob, "LICENSE")
|
40
40
|
|
41
41
|
actual = license_file.match
|
42
42
|
assert actual, "No match for #{expected}. Here's the test text:\n#{text}"
|
data/test/helper.rb
CHANGED
data/test/test_licensee.rb
CHANGED
@@ -15,13 +15,27 @@ class TestLicensee < Minitest::Test
|
|
15
15
|
Licensee.diff(fixture_path("licenses.git"))
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
context "confidence threshold" do
|
19
|
+
should "return the confidence threshold" do
|
20
|
+
assert_equal 90, Licensee.confidence_threshold
|
21
|
+
end
|
22
|
+
|
23
|
+
should "let the user override the confidence threshold" do
|
24
|
+
Licensee.confidence_threshold = 50
|
25
|
+
assert_equal 50, Licensee.confidence_threshold
|
26
|
+
Licensee.confidence_threshold = 90
|
27
|
+
end
|
20
28
|
end
|
21
29
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
30
|
+
context "npm-bower matcher" do
|
31
|
+
should "be disabled by default" do
|
32
|
+
refute Licensee.matchers.include? Licensee::NpmBowerMatcher
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be enable-able" do
|
36
|
+
Licensee.package_manager_files = true
|
37
|
+
assert Licensee.matchers.include? Licensee::NpmBowerMatcher
|
38
|
+
Licensee.package_manager_files = false
|
39
|
+
end
|
26
40
|
end
|
27
41
|
end
|
data/test/test_licensee_bin.rb
CHANGED
@@ -6,7 +6,7 @@ class TestLicenseeBin < Minitest::Test
|
|
6
6
|
Dir.chdir root
|
7
7
|
stdout,stderr,status = Open3.capture3("#{root}/bin/licensee")
|
8
8
|
assert stdout.include?("License: MIT"), "expected #{stdout} to include `License: MIT`"
|
9
|
-
assert stdout.include?("
|
9
|
+
assert stdout.include?("Matched file: LICENSE.md"), "expected #{stdout} to include `Matched file: LICENSE.md`"
|
10
10
|
assert_equal 0, status
|
11
11
|
end
|
12
12
|
end
|
@@ -6,7 +6,7 @@ class TestLicenseeCopyrightMatcher < Minitest::Test
|
|
6
6
|
def setup
|
7
7
|
text = "Copyright 2015 Ben Balter"
|
8
8
|
blob = FakeBlob.new(text)
|
9
|
-
@file = Licensee::
|
9
|
+
@file = Licensee::ProjectFile.new(blob, "LICENSE")
|
10
10
|
end
|
11
11
|
|
12
12
|
should "match the license" do
|
@@ -20,35 +20,35 @@ class TestLicenseeCopyrightMatcher < Minitest::Test
|
|
20
20
|
should "match Copyright (C) copyright notices" do
|
21
21
|
text = "Copyright (C) 2015 Ben Balter"
|
22
22
|
blob = FakeBlob.new(text)
|
23
|
-
file = Licensee::
|
23
|
+
file = Licensee::ProjectFile.new(blob, "LICENSE")
|
24
24
|
assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
|
25
25
|
end
|
26
26
|
|
27
27
|
should "match Copyright © copyright notices" do
|
28
28
|
text = "copyright © 2015 Ben Balter"
|
29
29
|
blob = FakeBlob.new(text)
|
30
|
-
file = Licensee::
|
30
|
+
file = Licensee::ProjectFile.new(blob, "LICENSE")
|
31
31
|
assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
|
32
32
|
end
|
33
33
|
|
34
34
|
should "not false positive" do
|
35
|
-
text = File.open(Licensee::
|
35
|
+
text = File.open(Licensee::License.find("mit").path).read.split("---").last
|
36
36
|
blob = FakeBlob.new(text)
|
37
|
-
file = Licensee::
|
37
|
+
file = Licensee::ProjectFile.new(blob, "LICENSE")
|
38
38
|
assert_equal nil, Licensee::CopyrightMatcher.match(file)
|
39
39
|
end
|
40
40
|
|
41
41
|
should "handle UTF-8 encoded copyright notices" do
|
42
42
|
text = "Copyright (c) 2010-2014 Simon Hürlimann"
|
43
43
|
blob = FakeBlob.new(text)
|
44
|
-
file = Licensee::
|
44
|
+
file = Licensee::ProjectFile.new(blob, "LICENSE")
|
45
45
|
assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
|
46
46
|
end
|
47
47
|
|
48
48
|
should "handle ASCII-8BIT encoded copyright notices" do
|
49
49
|
text = "Copyright \xC2\xA92015 Ben Balter`".force_encoding("ASCII-8BIT")
|
50
50
|
blob = FakeBlob.new(text)
|
51
|
-
file = Licensee::
|
51
|
+
file = Licensee::ProjectFile.new(blob, "LICENSE")
|
52
52
|
assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
|
53
53
|
end
|
54
54
|
end
|
@@ -3,9 +3,9 @@ require 'helper'
|
|
3
3
|
class TestLicenseeExactMatcher < Minitest::Test
|
4
4
|
|
5
5
|
def setup
|
6
|
-
text = File.open(Licensee::
|
6
|
+
text = File.open(Licensee::License.find("mit").path).read.split("---").last
|
7
7
|
blob = FakeBlob.new(text)
|
8
|
-
@mit = Licensee::
|
8
|
+
@mit = Licensee::ProjectFile.new(blob, "LICENSE")
|
9
9
|
end
|
10
10
|
|
11
11
|
should "match the license" do
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestLicenseeGemspecMatcher < Minitest::Test
|
4
|
+
def setup
|
5
|
+
Licensee.package_manager_files = true
|
6
|
+
end
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
Licensee.package_manager_files = false
|
10
|
+
end
|
11
|
+
|
12
|
+
should "detect its own license" do
|
13
|
+
root = File.expand_path "../", File.dirname(__FILE__)
|
14
|
+
project = Licensee::Project.new(root)
|
15
|
+
matcher = Licensee::GemspecMatcher.new(project.package_file)
|
16
|
+
assert_equal "mit", matcher.send(:license_property)
|
17
|
+
assert_equal "mit", matcher.match.key
|
18
|
+
end
|
19
|
+
end
|
@@ -3,9 +3,9 @@ require 'helper'
|
|
3
3
|
class TestLicenseeGitMatcher < Minitest::Test
|
4
4
|
|
5
5
|
def setup
|
6
|
-
text = license_from_path( Licensee::
|
6
|
+
text = license_from_path( Licensee::License.find("mit").path )
|
7
7
|
blob = FakeBlob.new(text)
|
8
|
-
@mit = Licensee::
|
8
|
+
@mit = Licensee::ProjectFile.new(blob, "LICENSE")
|
9
9
|
end
|
10
10
|
|
11
11
|
should "match the license" do
|
@@ -3,9 +3,9 @@ require 'helper'
|
|
3
3
|
class TestLicenseeLevenshteinMatcher < Minitest::Test
|
4
4
|
|
5
5
|
def setup
|
6
|
-
text = license_from_path( Licensee::
|
6
|
+
text = license_from_path( Licensee::License.find("mit").path )
|
7
7
|
blob = FakeBlob.new(text)
|
8
|
-
@mit = Licensee::
|
8
|
+
@mit = Licensee::ProjectFile.new(blob, "LICENSE")
|
9
9
|
end
|
10
10
|
|
11
11
|
should "match the license" do
|
@@ -22,8 +22,8 @@ class TestLicenseeLevenshteinMatcher < Minitest::Test
|
|
22
22
|
end
|
23
23
|
|
24
24
|
should "calculate length delta" do
|
25
|
-
isc = Licensee::
|
26
|
-
assert_equal 2, Licensee::LevenshteinMatcher.new(@mit).length_delta(Licensee::
|
25
|
+
isc = Licensee::License.find("isc")
|
26
|
+
assert_equal 2, Licensee::LevenshteinMatcher.new(@mit).length_delta(Licensee::License.find("mit"))
|
27
27
|
assert_equal 334, Licensee::LevenshteinMatcher.new(@mit).length_delta(isc)
|
28
28
|
end
|
29
29
|
|
@@ -88,4 +88,23 @@ class TestLicenseeLicense < Minitest::Test
|
|
88
88
|
assert_equal "Other", license.name
|
89
89
|
refute license.featured?
|
90
90
|
end
|
91
|
+
|
92
|
+
describe "class methods" do
|
93
|
+
should "know license names" do
|
94
|
+
assert_equal Array, Licensee::License.keys.class
|
95
|
+
assert_equal 19, Licensee::License.keys.size
|
96
|
+
end
|
97
|
+
|
98
|
+
should "load the licenses" do
|
99
|
+
assert_equal Array, Licensee::License.all.class
|
100
|
+
assert_equal 19, Licensee::License.all.size
|
101
|
+
assert_equal Licensee::License, Licensee::License.all.first.class
|
102
|
+
end
|
103
|
+
|
104
|
+
should "find a license" do
|
105
|
+
assert_equal "mit", Licensee::License.find("mit").key
|
106
|
+
assert_equal "mit", Licensee::License.find("MIT").key
|
107
|
+
assert_equal "mit", Licensee::License["mit"].key
|
108
|
+
end
|
109
|
+
end
|
91
110
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestLicenseeNpmBowerMatcher < Minitest::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
Licensee.package_manager_files = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
Licensee.package_manager_files = false
|
11
|
+
end
|
12
|
+
|
13
|
+
should "detect NPM files" do
|
14
|
+
project = Licensee::Project.new fixture_path "npm"
|
15
|
+
matcher = Licensee::NpmBowerMatcher.new(project.package_file)
|
16
|
+
assert_equal "mit", matcher.send(:license_property)
|
17
|
+
assert_equal "mit", matcher.match.key
|
18
|
+
end
|
19
|
+
|
20
|
+
should "detect Bower files" do
|
21
|
+
project = Licensee::Project.new fixture_path "bower"
|
22
|
+
matcher = Licensee::NpmBowerMatcher.new(project.package_file)
|
23
|
+
assert_equal "mit", matcher.send(:license_property)
|
24
|
+
assert_equal "mit", matcher.match.key
|
25
|
+
end
|
26
|
+
|
27
|
+
should "not err on non-spdx licenses" do
|
28
|
+
project = Licensee::Project.new fixture_path "npm-non-spdx"
|
29
|
+
matcher = Licensee::NpmBowerMatcher.new(project.package_file)
|
30
|
+
assert_equal "mit-1.0", matcher.send(:license_property)
|
31
|
+
assert_equal nil, matcher.match
|
32
|
+
end
|
33
|
+
end
|
@@ -28,7 +28,7 @@ class TestLicenseeProject < Minitest::Test
|
|
28
28
|
|
29
29
|
should "detect the license file" do
|
30
30
|
project = make_project "licenses.git", as_git
|
31
|
-
assert_instance_of Licensee::
|
31
|
+
assert_instance_of Licensee::ProjectFile, project.license_file
|
32
32
|
end
|
33
33
|
|
34
34
|
should "detect the license" do
|
@@ -36,24 +36,9 @@ class TestLicenseeProject < Minitest::Test
|
|
36
36
|
assert_equal "mit", project.license.key
|
37
37
|
end
|
38
38
|
|
39
|
-
should "return the license hash" do
|
40
|
-
project = make_project "licenses.git", as_git
|
41
|
-
assert_equal "LICENSE", project.send(:license_hash)[:name]
|
42
|
-
end
|
43
|
-
|
44
|
-
should "return the license blob" do
|
45
|
-
project = make_project "licenses.git", as_git
|
46
|
-
assert_equal 1077, project.send(:license_blob).size
|
47
|
-
end
|
48
|
-
|
49
|
-
should "return the license path" do
|
50
|
-
project = make_project "licenses.git", as_git
|
51
|
-
assert_equal "LICENSE", project.send(:license_path)
|
52
|
-
end
|
53
|
-
|
54
39
|
should "detect an atypically cased license file" do
|
55
40
|
project = make_project "case-sensitive.git", as_git
|
56
|
-
assert_instance_of Licensee::
|
41
|
+
assert_instance_of Licensee::ProjectFile, project.license_file
|
57
42
|
end
|
58
43
|
|
59
44
|
should "detect MIT-LICENSE licensed projects" do
|
@@ -83,29 +68,20 @@ class TestLicenseeProject < Minitest::Test
|
|
83
68
|
end
|
84
69
|
end
|
85
70
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
"
|
98
|
-
"
|
99
|
-
"
|
100
|
-
"MIT-LICENSE.txt" => 0.5,
|
101
|
-
"mit-license-foo.md" => 0.5,
|
102
|
-
"README.txt" => 0.0
|
103
|
-
}
|
104
|
-
|
105
|
-
EXPECTATIONS.each do |filename, expected|
|
106
|
-
should "score a license named `#{filename}` as `#{expected}`" do
|
107
|
-
assert_equal expected, Licensee::Project.match_license_file(filename)
|
108
|
-
end
|
71
|
+
describe "packages" do
|
72
|
+
|
73
|
+
def setup
|
74
|
+
Licensee.package_manager_files = true
|
75
|
+
end
|
76
|
+
|
77
|
+
def teardown
|
78
|
+
Licensee.package_manager_files = false
|
79
|
+
end
|
80
|
+
|
81
|
+
should "detect a package file" do
|
82
|
+
project = Licensee::Project.new fixture_path "npm"
|
83
|
+
assert_equal "package.json", project.package_file.filename
|
84
|
+
assert_equal "mit", project.license.key
|
109
85
|
end
|
110
86
|
end
|
111
87
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestLicenseeProjectFile < Minitest::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@repo = Rugged::Repository.new(fixture_path("licenses.git"))
|
7
|
+
blob = 'bcb552d06d9cf1cd4c048a6d3bf716849c2216cc'
|
8
|
+
@file = Licensee::ProjectFile.new(@repo.lookup(blob), "LICENSE")
|
9
|
+
@gpl = Licensee::License.find "GPL-3.0"
|
10
|
+
@mit = Licensee::License.find "MIT"
|
11
|
+
end
|
12
|
+
|
13
|
+
should "read the file" do
|
14
|
+
assert @file.contents =~ /MIT/
|
15
|
+
end
|
16
|
+
|
17
|
+
should "match the license" do
|
18
|
+
assert_equal "mit", @file.match.key
|
19
|
+
end
|
20
|
+
|
21
|
+
should "know the path" do
|
22
|
+
assert_equal "LICENSE", @file.path
|
23
|
+
end
|
24
|
+
|
25
|
+
should "diff the file" do
|
26
|
+
expected = "-Copyright (c) [year] [fullname]\n+Copyright (c) 2014 Ben Balter"
|
27
|
+
assert @file.diff.include?(expected)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "calculate confidence" do
|
31
|
+
assert_equal 94, @file.confidence
|
32
|
+
end
|
33
|
+
|
34
|
+
context "license filename scoring" do
|
35
|
+
|
36
|
+
EXPECTATIONS = {
|
37
|
+
"license" => 1.0,
|
38
|
+
"LICENCE" => 1.0,
|
39
|
+
"license.md" => 1.0,
|
40
|
+
"LICENSE.md" => 1.0,
|
41
|
+
"license.txt" => 1.0,
|
42
|
+
"unLICENSE" => 1.0,
|
43
|
+
"unlicence" => 1.0,
|
44
|
+
"COPYING" => 0.75,
|
45
|
+
"copyRIGHT" => 0.75,
|
46
|
+
"COPYRIGHT.txt" => 0.75,
|
47
|
+
"LICENSE-MIT" => 0.5,
|
48
|
+
"MIT-LICENSE.txt" => 0.5,
|
49
|
+
"mit-license-foo.md" => 0.5,
|
50
|
+
"README.txt" => 0.0
|
51
|
+
}
|
52
|
+
|
53
|
+
EXPECTATIONS.each do |filename, expected|
|
54
|
+
should "score a license named `#{filename}` as `#{expected}`" do
|
55
|
+
assert_equal expected, Licensee::ProjectFile.license_score(filename)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestLicenseeVendor < Minitest::Test
|
4
|
-
|
4
|
+
Licensee::License.send(:license_files).shuffle.each do |license|
|
5
5
|
|
6
6
|
should "detect the #{license} license" do
|
7
7
|
verify_license_file(license)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: licensee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0b1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Balter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rugged
|
@@ -109,15 +109,18 @@ files:
|
|
109
109
|
- lib/licensee.rb
|
110
110
|
- lib/licensee/filesystem_repository.rb
|
111
111
|
- lib/licensee/license.rb
|
112
|
-
- lib/licensee/license_file.rb
|
113
|
-
- lib/licensee/licenses.rb
|
114
112
|
- lib/licensee/matcher.rb
|
115
113
|
- lib/licensee/matchers/copyright_matcher.rb
|
116
114
|
- lib/licensee/matchers/exact_matcher.rb
|
115
|
+
- lib/licensee/matchers/gemspec_matcher.rb
|
117
116
|
- lib/licensee/matchers/git_matcher.rb
|
118
117
|
- lib/licensee/matchers/levenshtein_matcher.rb
|
118
|
+
- lib/licensee/matchers/npm_bower_matcher.rb
|
119
|
+
- lib/licensee/matchers/package_matcher.rb
|
119
120
|
- lib/licensee/project.rb
|
121
|
+
- lib/licensee/project_file.rb
|
120
122
|
- lib/licensee/version.rb
|
123
|
+
- test/fixtures/bower/bower.json
|
121
124
|
- test/fixtures/case-sensitive.git/HEAD
|
122
125
|
- test/fixtures/case-sensitive.git/config
|
123
126
|
- test/fixtures/case-sensitive.git/objects/01/7b4f1eebd1dcb735e950b1d01093e3e2bf85e9
|
@@ -168,19 +171,22 @@ files:
|
|
168
171
|
- test/fixtures/no-license.git/objects/e1/d9b2a3d41c2ea74a520e66da2b5c63b2f6202f
|
169
172
|
- test/fixtures/no-license.git/objects/ff/1592f44259635df9feda5e02853964b26f9e4d
|
170
173
|
- test/fixtures/no-license.git/refs/heads/master
|
174
|
+
- test/fixtures/npm-non-spdx/package.json
|
175
|
+
- test/fixtures/npm/package.json
|
171
176
|
- test/functions.rb
|
172
177
|
- test/helper.rb
|
173
178
|
- test/test_licensee.rb
|
174
179
|
- test/test_licensee_bin.rb
|
175
180
|
- test/test_licensee_copyright_matcher.rb
|
176
181
|
- test/test_licensee_exact_matcher.rb
|
182
|
+
- test/test_licensee_gemspec_matcher.rb
|
177
183
|
- test/test_licensee_git_matcher.rb
|
178
184
|
- test/test_licensee_levenshtein_matcher.rb
|
179
185
|
- test/test_licensee_license.rb
|
180
|
-
- test/test_licensee_license_file.rb
|
181
|
-
- test/test_licensee_licenses.rb
|
182
186
|
- test/test_licensee_matcher.rb
|
187
|
+
- test/test_licensee_npm_bower_matcher.rb
|
183
188
|
- test/test_licensee_project.rb
|
189
|
+
- test/test_licensee_project_file.rb
|
184
190
|
- test/test_licensee_vendor.rb
|
185
191
|
- vendor/choosealicense.com/_licenses/agpl-3.0.txt
|
186
192
|
- vendor/choosealicense.com/_licenses/apache-2.0.txt
|
@@ -216,9 +222,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
216
222
|
version: '0'
|
217
223
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
218
224
|
requirements:
|
219
|
-
- - "
|
225
|
+
- - ">"
|
220
226
|
- !ruby/object:Gem::Version
|
221
|
-
version:
|
227
|
+
version: 1.3.1
|
222
228
|
requirements: []
|
223
229
|
rubyforge_project:
|
224
230
|
rubygems_version: 2.4.8
|
@@ -1,52 +0,0 @@
|
|
1
|
-
class Licensee
|
2
|
-
class LicenseFile
|
3
|
-
attr_reader :blob, :path
|
4
|
-
|
5
|
-
def initialize(blob, options={})
|
6
|
-
@blob = blob
|
7
|
-
@path = options[:path]
|
8
|
-
end
|
9
|
-
|
10
|
-
def similarity(other)
|
11
|
-
blob.hashsig(Rugged::Blob::HashSignature::WHITESPACE_SMART)
|
12
|
-
other.hashsig ? blob.similarity(other.hashsig) : 0
|
13
|
-
rescue Rugged::InvalidError
|
14
|
-
0
|
15
|
-
end
|
16
|
-
|
17
|
-
# Raw file contents
|
18
|
-
def content
|
19
|
-
@contents ||= begin
|
20
|
-
blob.content.force_encoding("UTF-8")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
alias_method :to_s, :content
|
24
|
-
alias_method :contents, :content
|
25
|
-
|
26
|
-
# File content with all whitespace replaced with a single space
|
27
|
-
def content_normalized
|
28
|
-
@content_normalized ||= content.downcase.gsub(/\s+/, " ").strip
|
29
|
-
end
|
30
|
-
|
31
|
-
# Comptutes a diff between known license and project license
|
32
|
-
def diff(options={})
|
33
|
-
options = options.merge(:reverse => true)
|
34
|
-
blob.diff(match.body, options).to_s if match
|
35
|
-
end
|
36
|
-
|
37
|
-
# Determines which matching strategy to use, returns an instane of that matcher
|
38
|
-
def matcher
|
39
|
-
@matcher ||= Licensee.matchers.map { |m| m.new(self) }.find { |m| m.match }
|
40
|
-
end
|
41
|
-
|
42
|
-
# Returns an Licensee::License instance of the matches license
|
43
|
-
def match
|
44
|
-
@match ||= matcher.match if matcher
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns the percent confident with the match
|
48
|
-
def confidence
|
49
|
-
@condience ||= matcher.confidence if matcher
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/lib/licensee/licenses.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
class Licensee
|
2
|
-
class Licenses
|
3
|
-
class << self
|
4
|
-
|
5
|
-
# Returns an array of Licensee::License instances
|
6
|
-
def list
|
7
|
-
@licenses ||= begin
|
8
|
-
licenses = []
|
9
|
-
keys.each { |key| licenses.push License.new(key) }
|
10
|
-
licenses
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# Given a license key, attempt to return a matching Licensee::License instance
|
15
|
-
def find(key)
|
16
|
-
list.find { |l| l.key.downcase == key.downcase }
|
17
|
-
end
|
18
|
-
alias_method :[], :find
|
19
|
-
|
20
|
-
# Path to vendored licenses
|
21
|
-
def base
|
22
|
-
@base ||= File.expand_path "../../vendor/choosealicense.com/_licenses", File.dirname(__FILE__)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns a list of potential license keys, as vendored
|
26
|
-
def keys
|
27
|
-
@keys ||= begin
|
28
|
-
keyes = Dir.entries(base)
|
29
|
-
keyes.map! { |l| File.basename(l, ".txt").downcase }
|
30
|
-
keyes.reject! { |l| l =~ /^\./ || l.nil? }
|
31
|
-
keyes
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestLicenseeLicenseFile < Minitest::Test
|
4
|
-
|
5
|
-
def setup
|
6
|
-
@repo = Rugged::Repository.new(fixture_path("licenses.git"))
|
7
|
-
blob = 'bcb552d06d9cf1cd4c048a6d3bf716849c2216cc'
|
8
|
-
@file = Licensee::LicenseFile.new(@repo.lookup(blob), :path => "LICENSE")
|
9
|
-
@gpl = Licensee::Licenses.find "GPL-3.0"
|
10
|
-
@mit = Licensee::Licenses.find "MIT"
|
11
|
-
end
|
12
|
-
|
13
|
-
should "read the file" do
|
14
|
-
assert @file.contents =~ /MIT/
|
15
|
-
end
|
16
|
-
|
17
|
-
should "match the license" do
|
18
|
-
assert_equal "mit", @file.match.key
|
19
|
-
end
|
20
|
-
|
21
|
-
should "know the path" do
|
22
|
-
assert_equal "LICENSE", @file.path
|
23
|
-
end
|
24
|
-
|
25
|
-
should "diff the file" do
|
26
|
-
expected = "-Copyright (c) [year] [fullname]\n+Copyright (c) 2014 Ben Balter"
|
27
|
-
assert @file.diff.include?(expected)
|
28
|
-
end
|
29
|
-
|
30
|
-
should "calculate confidence" do
|
31
|
-
assert_equal 94, @file.confidence
|
32
|
-
end
|
33
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestLicenseeLicenses < Minitest::Test
|
4
|
-
|
5
|
-
should "know license names" do
|
6
|
-
assert_equal Array, Licensee::Licenses.keys.class
|
7
|
-
assert_equal 19, Licensee::Licenses.keys.size
|
8
|
-
end
|
9
|
-
|
10
|
-
should "load the licenses" do
|
11
|
-
assert_equal Array, Licensee::Licenses.list.class
|
12
|
-
assert_equal 19, Licensee::Licenses.list.size
|
13
|
-
assert_equal Licensee::License, Licensee::Licenses.list.first.class
|
14
|
-
end
|
15
|
-
|
16
|
-
should "find a license" do
|
17
|
-
assert_equal "mit", Licensee::Licenses.find("mit").key
|
18
|
-
assert_equal "mit", Licensee::Licenses.find("MIT").key
|
19
|
-
assert_equal "mit", Licensee::Licenses["mit"].key
|
20
|
-
end
|
21
|
-
end
|