licensee 8.9.2 → 9.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/bin/licensee +42 -28
  4. data/lib/licensee.rb +14 -28
  5. data/lib/licensee/content_helper.rb +38 -12
  6. data/lib/licensee/license.rb +22 -9
  7. data/lib/licensee/matchers.rb +14 -0
  8. data/lib/licensee/matchers/cabal.rb +16 -0
  9. data/lib/licensee/matchers/{copyright_matcher.rb → copyright.rb} +1 -5
  10. data/lib/licensee/matchers/{cran_matcher.rb → cran.rb} +1 -1
  11. data/lib/licensee/matchers/{dice_matcher.rb → dice.rb} +1 -7
  12. data/lib/licensee/matchers/{dist_zilla_matcher.rb → dist_zilla.rb} +1 -1
  13. data/lib/licensee/matchers/{exact_matcher.rb → exact.rb} +2 -1
  14. data/lib/licensee/matchers/gemspec.rb +24 -0
  15. data/lib/licensee/matchers/{package_matcher.rb → matcher.rb} +5 -3
  16. data/lib/licensee/matchers/{npm_bower_matcher.rb → npm_bower.rb} +2 -2
  17. data/lib/licensee/matchers/package.rb +22 -0
  18. data/lib/licensee/project_files.rb +8 -0
  19. data/lib/licensee/project_files/license_file.rb +22 -4
  20. data/lib/licensee/project_files/package_manager_file.rb +37 -0
  21. data/lib/licensee/project_files/project_file.rb +65 -0
  22. data/lib/licensee/project_files/{readme.rb → readme_file.rb} +2 -2
  23. data/lib/licensee/projects.rb +7 -0
  24. data/lib/licensee/projects/fs_project.rb +64 -27
  25. data/lib/licensee/projects/git_project.rb +49 -43
  26. data/lib/licensee/projects/project.rb +149 -0
  27. data/lib/licensee/version.rb +1 -1
  28. data/spec/bin_spec.rb +9 -2
  29. data/spec/fixtures/crlf-license/LICENSE +674 -0
  30. data/spec/fixtures/fcpl-modified-mpl/LICENSE +193 -193
  31. data/spec/fixtures/ipsum.txt +19 -0
  32. data/spec/fixtures/license-in-parent-folder/LICENSE.txt +21 -0
  33. data/spec/fixtures/license-in-parent-folder/license-folder/LICENSE.txt +21 -0
  34. data/spec/fixtures/multiple-license-files/LICENSE +362 -0
  35. data/spec/fixtures/multiple-license-files/LICENSE.txt +21 -0
  36. data/spec/integration_spec.rb +57 -22
  37. data/spec/licensee/content_helper_spec.rb +33 -9
  38. data/spec/licensee/license_spec.rb +8 -1
  39. data/spec/licensee/matchers/cabal_matcher_spec.rb +45 -0
  40. data/spec/licensee/matchers/copyright_matcher_spec.rb +1 -1
  41. data/spec/licensee/matchers/cran_matcher_spec.rb +11 -2
  42. data/spec/licensee/matchers/dice_matcher_spec.rb +1 -2
  43. data/spec/licensee/matchers/dist_zilla_matcher_spec.rb +11 -2
  44. data/spec/licensee/matchers/exact_matcher_spec.rb +1 -1
  45. data/spec/licensee/matchers/gemspec_matcher_spec.rb +19 -1
  46. data/spec/licensee/matchers/npm_bower_matcher_spec.rb +23 -6
  47. data/spec/licensee/matchers/package_matcher_spec.rb +31 -2
  48. data/spec/licensee/project_files/license_file_spec.rb +62 -6
  49. data/spec/licensee/project_files/package_info_spec.rb +10 -1
  50. data/spec/{project_file_spec.rb → licensee/project_files/project_file_spec.rb} +14 -1
  51. data/spec/licensee/project_files/readme_spec.rb +1 -1
  52. data/spec/licensee/project_spec.rb +134 -9
  53. data/spec/licensee_spec.rb +4 -3
  54. data/spec/spec_helper.rb +12 -23
  55. data/spec/vendored_license_spec.rb +16 -13
  56. metadata +29 -17
  57. data/lib/licensee/matchers/gemspec_matcher.rb +0 -19
  58. data/lib/licensee/project.rb +0 -87
  59. data/lib/licensee/project_file.rb +0 -39
  60. data/lib/licensee/project_files/package_info.rb +0 -31
@@ -11,11 +11,13 @@ RSpec.describe Licensee::ContentHelper do
11
11
  let(:content) do
12
12
  <<-EOS.freeze.gsub(/^\s*/, '')
13
13
  # The MIT License
14
- =================
14
+ =================
15
15
 
16
- Copyright 2016 Ben Balter
16
+ Copyright 2016 Ben Balter
17
+ *************************
17
18
 
18
19
  The made
20
+ * * * *
19
21
  up license.
20
22
  -----------
21
23
  EOS
@@ -31,15 +33,11 @@ EOS
31
33
  expect(subject.length).to eql(20)
32
34
  end
33
35
 
34
- it 'knows the max delta' do
35
- expect(subject.max_delta).to eql(1)
36
- end
37
-
38
36
  context 'a very long license' do
39
37
  let(:content) { 'license' * 1000 }
40
38
 
41
- it 'does not return a max delta larger than 150' do
42
- expect(subject.max_delta).to eql(150)
39
+ it 'returns the max delta' do
40
+ expect(subject.max_delta).to eql(140)
43
41
  end
44
42
  end
45
43
 
@@ -54,7 +52,19 @@ EOS
54
52
  end
55
53
 
56
54
  it 'calculates the hash' do
57
- expect(subject.hash).to eql('3c59634b9fae4396a76a978f3f6aa718ed790a9a')
55
+ content_hash = '3c59634b9fae4396a76a978f3f6aa718ed790a9a'
56
+ expect(subject.content_hash).to eql(content_hash)
57
+ end
58
+
59
+ it 'wraps' do
60
+ content = Licensee::ContentHelper.wrap(mit.content, 40)
61
+ lines = content.split("\n")
62
+ expect(lines.first.length).to be <= 40
63
+ end
64
+
65
+ it 'formats percents' do
66
+ percent = Licensee::ContentHelper.format_percent(12.3456789)
67
+ expect(percent).to eql('12.35%')
58
68
  end
59
69
 
60
70
  context 'normalizing' do
@@ -72,6 +82,19 @@ EOS
72
82
 
73
83
  it 'strips HRs' do
74
84
  expect(normalized_content).to_not match '---'
85
+ expect(normalized_content).to_not match '==='
86
+ expect(normalized_content).to_not include '***'
87
+ expect(normalized_content).to_not include '* *'
88
+ end
89
+
90
+ it 'strips formatting from the MPL' do
91
+ license = Licensee::License.find('mpl-2.0')
92
+ expect(license.content_normalized).to_not include('* *')
93
+ end
94
+
95
+ it 'wraps' do
96
+ lines = mit.content_normalized(wrap: 40).split("\n")
97
+ expect(lines.first.length).to be <= 40
75
98
  end
76
99
 
77
100
  it 'squeezes whitespace' do
@@ -80,6 +103,7 @@ EOS
80
103
 
81
104
  it 'strips whitespace' do
82
105
  expect(normalized_content).to_not match(/\n/)
106
+ expect(normalized_content).to_not match(/\t/)
83
107
  end
84
108
 
85
109
  it 'strips markdown headings' do
@@ -12,6 +12,7 @@ RSpec.describe Licensee::License do
12
12
  let(:unlicense) { described_class.find('unlicense') }
13
13
  let(:other) { described_class.find('other') }
14
14
  let(:gpl) { described_class.find('gpl-3.0') }
15
+ let(:lgpl) { described_class.find('lgpl-3.0') }
15
16
 
16
17
  let(:license_dir) do
17
18
  File.expand_path 'vendor/choosealicense.com/_licenses', project_root
@@ -169,6 +170,11 @@ RSpec.describe Licensee::License do
169
170
  expect(gpl).to be_gpl
170
171
  end
171
172
 
173
+ it 'knows a license is lgpl' do
174
+ expect(mit).to_not be_gpl
175
+ expect(lgpl).to be_lgpl
176
+ end
177
+
172
178
  it 'knows if a license is CC' do
173
179
  expect(gpl).to_not be_creative_commons
174
180
  expect(cc_by).to be_creative_commons
@@ -185,7 +191,8 @@ RSpec.describe Licensee::License do
185
191
  end
186
192
 
187
193
  it 'computes the hash' do
188
- expect(mit.hash).to eql('d64f3bb4282a97b37454b5bb96a8a264a3363dc3')
194
+ content_hash = 'd64f3bb4282a97b37454b5bb96a8a264a3363dc3'
195
+ expect(mit.content_hash).to eql(content_hash)
189
196
  end
190
197
 
191
198
  context 'with content stubbed' do
@@ -0,0 +1,45 @@
1
+ RSpec.describe Licensee::Matchers::Cabal do
2
+ let(:content) { 'license: mit' }
3
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.txt') }
4
+ let(:mit) { Licensee::License.find('mit') }
5
+ let(:no_license) { Licensee::License.find('no-license') }
6
+ subject { described_class.new(file) }
7
+
8
+ it 'matches' do
9
+ expect(subject.match).to eql(mit)
10
+ end
11
+
12
+ it 'has a confidence' do
13
+ expect(subject.confidence).to eql(90)
14
+ end
15
+
16
+ {
17
+ 'whitespace' => 'license : mit',
18
+ 'no whitespace' => 'license:mit',
19
+ 'leading whitespace' => ' license:mit'
20
+ }.each do |description, license_declaration|
21
+ context "with a #{description} declaration" do
22
+ let(:content) { license_declaration }
23
+
24
+ it 'matches' do
25
+ expect(subject.match).to eql(mit)
26
+ end
27
+ end
28
+ end
29
+
30
+ context 'no license field' do
31
+ let(:content) { 'foo: bar' }
32
+
33
+ it 'returns nil' do
34
+ expect(subject.match).to be_nil
35
+ end
36
+ end
37
+
38
+ context 'an unknown license' do
39
+ let(:content) { 'license: foo' }
40
+
41
+ it 'returns other' do
42
+ expect(subject.match).to eql(Licensee::License.find('other'))
43
+ end
44
+ end
45
+ end
@@ -1,6 +1,6 @@
1
1
  RSpec.describe Licensee::Matchers::Copyright do
2
2
  let(:content) { 'Copyright 2015 Ben Balter' }
3
- let(:file) { Licensee::Project::LicenseFile.new(content, 'LICENSE.txt') }
3
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.txt') }
4
4
  let(:mit) { Licensee::License.find('mit') }
5
5
  let(:no_license) { Licensee::License.find('no-license') }
6
6
 
@@ -3,7 +3,7 @@ RSpec.describe Licensee::Matchers::Cran do
3
3
  let(:gpl2) { Licensee::License.find('gpl-2.0') }
4
4
  let(:gpl3) { Licensee::License.find('gpl-3.0') }
5
5
  let(:content) { "License: MIT + file LICENSE\nPackage: test" }
6
- let(:file) { Licensee::Project::LicenseFile.new(content, 'DESCRIPTION') }
6
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'DESCRIPTION') }
7
7
  subject { described_class.new(file) }
8
8
 
9
9
  it 'stores the file' do
@@ -26,7 +26,8 @@ RSpec.describe Licensee::Matchers::Cran do
26
26
  'GPL (>=2) + file LICENSE' => Licensee::License.find('gpl-2.0'),
27
27
  'GPL (>=3)' => Licensee::License.find('gpl-3.0'),
28
28
  'GPL-2' => Licensee::License.find('gpl-2.0'),
29
- 'GPL-3' => Licensee::License.find('gpl-3.0')
29
+ 'GPL-3' => Licensee::License.find('gpl-3.0'),
30
+ 'Foo' => Licensee::License.find('other')
30
31
  }.each do |license_declaration, license|
31
32
  context "with '#{license_declaration}' declaration" do
32
33
  let(:content) { "Package: test\nLicense: #{license_declaration}" }
@@ -36,4 +37,12 @@ RSpec.describe Licensee::Matchers::Cran do
36
37
  end
37
38
  end
38
39
  end
40
+
41
+ context 'with no license field' do
42
+ let(:content) { 'Package: test' }
43
+
44
+ it 'returns nil' do
45
+ expect(subject.match).to be_nil
46
+ end
47
+ end
39
48
  end
@@ -5,7 +5,7 @@ RSpec.describe Licensee::Matchers::Dice do
5
5
  let(:cc_by) { Licensee::License.find('cc-by-4.0') }
6
6
  let(:cc_by_sa) { Licensee::License.find('cc-by-sa-4.0') }
7
7
  let(:content) { sub_copyright_info(gpl.content) }
8
- let(:file) { Licensee::Project::LicenseFile.new(content, 'LICENSE.txt') }
8
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.txt') }
9
9
  subject { described_class.new(file) }
10
10
 
11
11
  it 'stores the file' do
@@ -50,7 +50,6 @@ RSpec.describe Licensee::Matchers::Dice do
50
50
  end
51
51
 
52
52
  it "doesn't match" do
53
- skip 'Stacked MIT + GPL not properly detected'
54
53
  expect(content).to_not be_detected_as(gpl)
55
54
  expect(subject.match).to eql(nil)
56
55
  expect(subject.matches).to be_empty
@@ -1,7 +1,7 @@
1
1
  RSpec.describe Licensee::Matchers::DistZilla do
2
2
  let(:mit) { Licensee::License.find('mit') }
3
3
  let(:content) { 'license = MIT' }
4
- let(:file) { Licensee::Project::LicenseFile.new(content, 'dist.ini') }
4
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'dist.ini') }
5
5
  subject { described_class.new(file) }
6
6
 
7
7
  it 'stores the file' do
@@ -18,7 +18,8 @@ RSpec.describe Licensee::Matchers::DistZilla do
18
18
 
19
19
  {
20
20
  'spdx name' => ['license = MIT', 'mit'],
21
- 'non spdx name' => ['license = Mozilla_2_0', 'mpl-2.0']
21
+ 'non spdx name' => ['license = Mozilla_2_0', 'mpl-2.0'],
22
+ 'other license' => ['license = Foo', 'other']
22
23
  }.each do |description, license_declaration_and_key|
23
24
  context "with a #{description}" do
24
25
  let(:content) { license_declaration_and_key[0] }
@@ -29,4 +30,12 @@ RSpec.describe Licensee::Matchers::DistZilla do
29
30
  end
30
31
  end
31
32
  end
33
+
34
+ context 'no license field' do
35
+ let(:content) { 'foo = bar' }
36
+
37
+ it 'returns nil' do
38
+ expect(subject.match).to be_nil
39
+ end
40
+ end
32
41
  end
@@ -1,7 +1,7 @@
1
1
  RSpec.describe Licensee::Matchers::Exact do
2
2
  let(:mit) { Licensee::License.find('mit') }
3
3
  let(:content) { sub_copyright_info(mit.content) }
4
- let(:file) { Licensee::Project::LicenseFile.new(content, 'LICENSE.txt') }
4
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.txt') }
5
5
  subject { described_class.new(file) }
6
6
 
7
7
  it 'stores the file' do
@@ -1,7 +1,9 @@
1
1
  RSpec.describe Licensee::Matchers::Gemspec do
2
2
  let(:mit) { Licensee::License.find('mit') }
3
3
  let(:content) { "s.license = 'mit'" }
4
- let(:file) { Licensee::Project::LicenseFile.new(content, 'project.gemspec') }
4
+ let(:file) do
5
+ Licensee::ProjectFiles::LicenseFile.new(content, 'project.gemspec')
6
+ end
5
7
  subject { described_class.new(file) }
6
8
 
7
9
  it 'matches' do
@@ -26,4 +28,20 @@ RSpec.describe Licensee::Matchers::Gemspec do
26
28
  end
27
29
  end
28
30
  end
31
+
32
+ context 'no license field' do
33
+ let(:content) { "s.foo = 'bar'" }
34
+
35
+ it 'returns nil' do
36
+ expect(subject.match).to be_nil
37
+ end
38
+ end
39
+
40
+ context 'an unknown license' do
41
+ let(:content) { "s.license = 'foo'" }
42
+
43
+ it 'returns other' do
44
+ expect(subject.match).to eql(Licensee::License.find('other'))
45
+ end
46
+ end
29
47
  end
@@ -1,6 +1,6 @@
1
1
  RSpec.describe Licensee::Matchers::NpmBower do
2
2
  let(:content) { '"license": "mit"' }
3
- let(:file) { Licensee::Project::LicenseFile.new(content, 'LICENSE.txt') }
3
+ let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.txt') }
4
4
  let(:mit) { Licensee::License.find('mit') }
5
5
  let(:no_license) { Licensee::License.find('no-license') }
6
6
  subject { described_class.new(file) }
@@ -14,11 +14,12 @@ RSpec.describe Licensee::Matchers::NpmBower do
14
14
  end
15
15
 
16
16
  {
17
- 'double quotes' => '"license": "mit"',
18
- 'single quotes' => "'license': 'mit'",
19
- 'mixed quotes' => "'license': \"mit\"",
20
- 'whitespace' => "'license' : 'mit'",
21
- 'no whitespace' => "'license':'mit'"
17
+ 'double quotes' => '"license": "mit"',
18
+ 'single quotes' => "'license': 'mit'",
19
+ 'mixed quotes' => "'license': \"mit\"",
20
+ 'whitespace' => "'license' : 'mit'",
21
+ 'no whitespace' => "'license':'mit'",
22
+ 'leading whitespace' => " 'license':'mit'"
22
23
  }.each do |description, license_declaration|
23
24
  context "with a #{description} declaration" do
24
25
  let(:content) { license_declaration }
@@ -28,4 +29,20 @@ RSpec.describe Licensee::Matchers::NpmBower do
28
29
  end
29
30
  end
30
31
  end
32
+
33
+ context 'no license field' do
34
+ let(:content) { 'foo: bar' }
35
+
36
+ it 'returns nil' do
37
+ expect(subject.match).to be_nil
38
+ end
39
+ end
40
+
41
+ context 'an unknown license' do
42
+ let(:content) { "'license': 'foo'" }
43
+
44
+ it 'returns other' do
45
+ expect(subject.match).to eql(Licensee::License.find('other'))
46
+ end
47
+ end
31
48
  end
@@ -1,9 +1,14 @@
1
1
  RSpec.describe Licensee::Matchers::Package do
2
2
  let(:mit) { Licensee::License.find('mit') }
3
3
  let(:content) { '' }
4
- let(:file) { Licensee::Project::LicenseFile.new(content, 'project.gemspec') }
4
+ let(:file) do
5
+ Licensee::ProjectFiles::LicenseFile.new(content, 'project.gemspec')
6
+ end
7
+ let(:license_property) { 'mit' }
5
8
  subject { described_class.new(file) }
6
- before { allow(subject).to receive(:license_property).and_return('mit') }
9
+ before do
10
+ allow(subject).to receive(:license_property).and_return(license_property)
11
+ end
7
12
 
8
13
  it 'matches' do
9
14
  expect(subject.match).to eql(mit)
@@ -12,4 +17,28 @@ RSpec.describe Licensee::Matchers::Package do
12
17
  it 'has confidence' do
13
18
  expect(subject.confidence).to eql(90)
14
19
  end
20
+
21
+ context 'with a nil license property' do
22
+ let(:license_property) { nil }
23
+
24
+ it 'matches to nil' do
25
+ expect(subject.match).to be_nil
26
+ end
27
+ end
28
+
29
+ context 'with an empty license property' do
30
+ let(:license_property) { '' }
31
+
32
+ it 'matches to nil' do
33
+ expect(subject.match).to be_nil
34
+ end
35
+ end
36
+
37
+ context 'with an unmatched license proprerty' do
38
+ let(:license_property) { 'foo' }
39
+
40
+ it 'matches to other' do
41
+ expect(subject.match).to eql(Licensee::License.find('other'))
42
+ end
43
+ end
15
44
  end
@@ -1,4 +1,4 @@
1
- RSpec.describe Licensee::Project::LicenseFile do
1
+ RSpec.describe Licensee::ProjectFiles::LicenseFile do
2
2
  let(:filename) { 'LICENSE.txt' }
3
3
  let(:mit) { Licensee::License.find('mit') }
4
4
  let(:content) { sub_copyright_info(mit.content) }
@@ -31,7 +31,8 @@ RSpec.describe Licensee::Project::LicenseFile do
31
31
  end
32
32
 
33
33
  it 'creates the hash' do
34
- expect(subject.hash).to eql('d64f3bb4282a97b37454b5bb96a8a264a3363dc3')
34
+ content_hash = 'd64f3bb4282a97b37454b5bb96a8a264a3363dc3'
35
+ expect(subject.content_hash).to eql(content_hash)
35
36
  end
36
37
 
37
38
  context 'filename scoring' do
@@ -52,10 +53,10 @@ RSpec.describe Licensee::Project::LicenseFile do
52
53
  'copying.image' => 0.5,
53
54
  'COPYRIGHT.go' => 0.5,
54
55
  'LICENSE-MIT' => 0.4,
55
- 'MIT-LICENSE.txt' => 0.4,
56
+ 'MIT-LICENSE.txt' => 0.3,
56
57
  'mit-license-foo.md' => 0.4,
57
- 'COPYING-GPL' => 0.3,
58
- 'COPYRIGHT-BSD' => 0.3,
58
+ 'COPYING-GPL' => 0.35,
59
+ 'COPYRIGHT-BSD' => 0.35,
59
60
  'OFL.md' => 0.2,
60
61
  'ofl.textile' => 0.1,
61
62
  'ofl' => 0.05,
@@ -133,7 +134,7 @@ RSpec.describe Licensee::Project::LicenseFile do
133
134
  end
134
135
 
135
136
  context 'CC false positives' do
136
- let(:regex) { Licensee::Project::LicenseFile::CC_FALSE_POSITIVE_REGEX }
137
+ let(:regex) { Licensee::ProjectFiles::LicenseFile::CC_FALSE_POSITIVE_REGEX }
137
138
 
138
139
  it "knows MIT isn't a potential false positive" do
139
140
  expect(subject.content).to_not match(regex)
@@ -182,4 +183,59 @@ Creative Commons Attribution-NonCommercial 4.0
182
183
  end
183
184
  end
184
185
  end
186
+
187
+ context 'LGPL' do
188
+ let(:lgpl) { Licensee::License.find('lgpl-3.0') }
189
+ let(:content) { sub_copyright_info(lgpl.content) }
190
+
191
+ context 'with a COPYING.lesser file' do
192
+ let(:filename) { 'COPYING.lesser' }
193
+
194
+ it 'knows when a license file is LGPL' do
195
+ expect(subject).to be_lgpl
196
+ end
197
+
198
+ context 'with non-lgpl content' do
199
+ let(:content) { sub_copyright_info(mit.content) }
200
+
201
+ it 'is not lgpl' do
202
+ expect(subject).to_not be_lgpl
203
+ end
204
+ end
205
+ end
206
+
207
+ context 'with a different file name' do
208
+ let(:filename) { 'COPYING' }
209
+
210
+ it 'is not lgpl' do
211
+ expect(subject).to_not be_lgpl
212
+ end
213
+ end
214
+ end
215
+
216
+ context 'GPL' do
217
+ let(:gpl) { Licensee::License.find('gpl-3.0') }
218
+ let(:content) { sub_copyright_info(gpl.content) }
219
+
220
+ it 'knows its GPL' do
221
+ expect(subject).to be_gpl
222
+ end
223
+
224
+ context 'another license' do
225
+ let(:content) { sub_copyright_info(mit.content) }
226
+
227
+ it 'is not GPL' do
228
+ expect(subject).to_not be_gpl
229
+ end
230
+ end
231
+ end
232
+
233
+ context 'an unknown license' do
234
+ let(:content) { 'foo' }
235
+ let(:other) { Licensee::License.find('other') }
236
+
237
+ it 'matches to other' do
238
+ expect(subject.license).to eql(other)
239
+ end
240
+ end
185
241
  end