licensee 4.9.0 → 5.0.0b1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|