licensee 9.6.0 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/lib/licensee.rb +5 -1
  3. data/lib/licensee/content_helper.rb +7 -1
  4. data/lib/licensee/matchers.rb +1 -0
  5. data/lib/licensee/matchers/gemspec.rb +31 -5
  6. data/lib/licensee/matchers/npm_bower.rb +1 -1
  7. data/lib/licensee/matchers/spdx.rb +16 -0
  8. data/lib/licensee/project_files/license_file.rb +6 -6
  9. data/lib/licensee/project_files/package_manager_file.rb +13 -8
  10. data/lib/licensee/project_files/project_file.rb +1 -1
  11. data/lib/licensee/projects.rb +1 -0
  12. data/lib/licensee/projects/github_project.rb +47 -0
  13. data/lib/licensee/version.rb +1 -1
  14. data/spec/bin_spec.rb +2 -1
  15. data/spec/fixtures/apache-with-readme-notice/LICENSE.header +16 -0
  16. data/spec/fixtures/markdown-gpl/LICENSE.md +361 -0
  17. data/spec/fixtures/webmock/licensee.json +26 -0
  18. data/spec/integration_spec.rb +9 -0
  19. data/spec/licensee/content_helper_spec.rb +5 -1
  20. data/spec/licensee/license_spec.rb +3 -3
  21. data/spec/licensee/matchers/gemspec_matcher_spec.rb +11 -1
  22. data/spec/licensee/matchers/npm_bower_matcher_spec.rb +11 -2
  23. data/spec/licensee/matchers/spdx_matcher_spec.rb +41 -0
  24. data/spec/licensee/project_files/license_file_spec.rb +3 -3
  25. data/spec/licensee/project_spec.rb +32 -5
  26. data/spec/licensee/projects/github_project_spec.rb +109 -0
  27. data/spec/licensee_spec.rb +15 -3
  28. data/spec/spec_helper.rb +20 -0
  29. data/vendor/choosealicense.com/_licenses/afl-3.0.txt +168 -41
  30. data/vendor/choosealicense.com/_licenses/apache-2.0.txt +2 -2
  31. data/vendor/choosealicense.com/_licenses/bsd-2-clause.txt +1 -1
  32. data/vendor/choosealicense.com/_licenses/bsd-3-clause-clear.txt +25 -25
  33. data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +1 -1
  34. data/vendor/choosealicense.com/_licenses/ecl-2.0.txt +1 -1
  35. data/vendor/choosealicense.com/_licenses/epl-1.0.txt +59 -59
  36. data/vendor/choosealicense.com/_licenses/epl-2.0.txt +311 -0
  37. data/vendor/choosealicense.com/_licenses/gpl-2.0.txt +3 -2
  38. data/vendor/choosealicense.com/_licenses/gpl-3.0.txt +1 -1
  39. data/vendor/choosealicense.com/_licenses/isc.txt +1 -1
  40. data/vendor/choosealicense.com/_licenses/mit.txt +2 -2
  41. data/vendor/choosealicense.com/_licenses/ms-pl.txt +52 -22
  42. data/vendor/choosealicense.com/_licenses/ms-rl.txt +64 -21
  43. data/vendor/choosealicense.com/_licenses/ncsa.txt +3 -3
  44. data/vendor/choosealicense.com/_licenses/wtfpl.txt +1 -1
  45. metadata +41 -5
@@ -0,0 +1,26 @@
1
+ [
2
+ {
3
+ "name": "LICENSE.txt",
4
+ "path": "LICENSE.txt",
5
+ "sha": "sha1",
6
+ "size": 1072,
7
+ "url": "https://api.github.com/repos/benbalter/licensee/contents/LICENSE.txt?ref=master",
8
+ "html_url": "https://github.com/benbalter/licensee/blob/master/LICENSE.txt",
9
+ "git_url": "https://api.github.com/repos/benbalter/licensee/git/blobs/sha1",
10
+ "download_url": "https://raw.githubusercontent.com/benbalter/licensee/master/LICENSE.txt",
11
+ "type": "file",
12
+ "_links": {}
13
+ },
14
+ {
15
+ "name": "README.md",
16
+ "path": "README.md",
17
+ "sha": "sha2",
18
+ "size": 13420,
19
+ "url": "https://api.github.com/repos/benbalter/licensee/contents/README.md?ref=master",
20
+ "html_url": "https://github.com/benbalter/licensee/blob/master/README.md",
21
+ "git_url": "https://api.github.com/repos/benbalter/licensee/git/blobs/sha2",
22
+ "download_url": "https://raw.githubusercontent.com/benbalter/licensee/master/README.md",
23
+ "type": "file",
24
+ "_links": {}
25
+ }
26
+ ]
@@ -177,6 +177,15 @@ RSpec.describe 'integration test' do
177
177
  expect(subject.license).to eql(license)
178
178
  end
179
179
  end
180
+
181
+ context 'GPL2 with Markdown formatting' do
182
+ let(:license) { Licensee::License.find('gpl-2.0') }
183
+ let(:fixture) { 'markdown-gpl' }
184
+
185
+ it 'matches to GPL2' do
186
+ expect(subject.license).to eql(license)
187
+ end
188
+ end
180
189
  end
181
190
 
182
191
  context 'with the license file stubbed' do
@@ -44,7 +44,7 @@ LICENSE
44
44
  end
45
45
 
46
46
  it 'knows the length delta' do
47
- expect(subject.length_delta(mit)).to eql(1000)
47
+ expect(subject.length_delta(mit)).to eql(999)
48
48
  expect(subject.length_delta(subject)).to eql(0)
49
49
  end
50
50
 
@@ -116,6 +116,10 @@ LICENSE
116
116
  expect(normalized_content).to_not match(/all rights reserved/i)
117
117
  end
118
118
 
119
+ it 'strips markup' do
120
+ expect(normalized_content).to_not match(/[*=_-]+/)
121
+ end
122
+
119
123
  Licensee::License.all(hidden: true).each do |license|
120
124
  context license.name do
121
125
  let(:stripped_content) { subject.content_without_title_and_version }
@@ -1,6 +1,6 @@
1
1
  RSpec.describe Licensee::License do
2
- let(:license_count) { 33 }
3
- let(:hidden_license_count) { 21 }
2
+ let(:license_count) { 34 }
3
+ let(:hidden_license_count) { 22 }
4
4
  let(:featured_license_count) { 3 }
5
5
  let(:pseudo_license_count) { 2 }
6
6
  let(:non_featured_license_count) do
@@ -13,6 +13,7 @@ RSpec.describe Licensee::License do
13
13
  let(:other) { described_class.find('other') }
14
14
  let(:gpl) { described_class.find('gpl-3.0') }
15
15
  let(:lgpl) { described_class.find('lgpl-3.0') }
16
+ let(:content_hash) { '46cdc03462b9af57968df67b450cc4372ac41f53' }
16
17
 
17
18
  let(:license_dir) do
18
19
  File.expand_path 'vendor/choosealicense.com/_licenses', project_root
@@ -242,7 +243,6 @@ RSpec.describe Licensee::License do
242
243
  end
243
244
 
244
245
  it 'computes the hash' do
245
- content_hash = 'd64f3bb4282a97b37454b5bb96a8a264a3363dc3'
246
246
  expect(mit.content_hash).to eql(content_hash)
247
247
  end
248
248
 
@@ -18,7 +18,9 @@ RSpec.describe Licensee::Matchers::Gemspec do
18
18
  'as spec.' => "spec.license = 'mit'",
19
19
  'double quotes' => 's.license = "mit"',
20
20
  'no whitespace' => "s.license='mit'",
21
- 'uppercase' => "s.license = 'MIT'"
21
+ 'uppercase' => "s.license = 'MIT'",
22
+ 'array' => "s.licenses = ['mit']",
23
+ 'frozen' => "s.license = 'mit'.freeze"
22
24
  }.each do |description, license_declaration|
23
25
  context "with a #{description} declaration" do
24
26
  let(:content) { license_declaration }
@@ -44,4 +46,12 @@ RSpec.describe Licensee::Matchers::Gemspec do
44
46
  expect(subject.match).to eql(Licensee::License.find('other'))
45
47
  end
46
48
  end
49
+
50
+ context 'a licenses property with multiple licenses' do
51
+ let(:content) { "s.licenses = ['mit', 'bsd-3-clause']" }
52
+
53
+ it 'returns other' do
54
+ expect(subject.match).to eql(Licensee::License.find('other'))
55
+ end
56
+ end
47
57
  end
@@ -2,7 +2,8 @@ RSpec.describe Licensee::Matchers::NpmBower do
2
2
  let(:content) { '"license": "mit"' }
3
3
  let(:file) { Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.txt') }
4
4
  let(:mit) { Licensee::License.find('mit') }
5
- let(:no_license) { Licensee::License.find('no-license') }
5
+ let(:other) { Licensee::License.find('other') }
6
+
6
7
  subject { described_class.new(file) }
7
8
 
8
9
  it 'matches' do
@@ -42,7 +43,15 @@ RSpec.describe Licensee::Matchers::NpmBower do
42
43
  let(:content) { "'license': 'foo'" }
43
44
 
44
45
  it 'returns other' do
45
- expect(subject.match).to eql(Licensee::License.find('other'))
46
+ expect(subject.match).to eql(other)
47
+ end
48
+ end
49
+
50
+ context 'a license expression' do
51
+ let(:content) { "'license': '(MIT OR Apache-2.0 OR AGPL-3.0+)'" }
52
+
53
+ it 'returns other' do
54
+ expect(subject.match).to eql(other)
46
55
  end
47
56
  end
48
57
  end
@@ -0,0 +1,41 @@
1
+ RSpec.describe Licensee::Matchers::Spdx do
2
+ let(:content) { 'PackageLicenseDeclared: MIT' }
3
+ let(:file) do
4
+ Licensee::ProjectFiles::LicenseFile.new(content, 'LICENSE.spdx')
5
+ end
6
+ let(:mit) { Licensee::License.find('mit') }
7
+ let(:other) { Licensee::License.find('other') }
8
+ subject { described_class.new(file) }
9
+
10
+ it 'matches' do
11
+ expect(subject.match).to eql(mit)
12
+ end
13
+
14
+ it 'has a confidence' do
15
+ expect(subject.confidence).to eql(90)
16
+ end
17
+
18
+ context 'no license field' do
19
+ let(:content) { 'foo: bar' }
20
+
21
+ it 'returns nil' do
22
+ expect(subject.match).to be_nil
23
+ end
24
+ end
25
+
26
+ context 'an unknown license' do
27
+ let(:content) { 'PackageLicenseDeclared: xyz' }
28
+
29
+ it 'returns other' do
30
+ expect(subject.match).to eql(other)
31
+ end
32
+ end
33
+
34
+ context 'a license expression' do
35
+ let(:content) { 'PackageLicenseDeclared: (MIT OR Apache-2.0)' }
36
+
37
+ it 'returns other' do
38
+ expect(subject.match).to eql(other)
39
+ end
40
+ end
41
+ end
@@ -2,6 +2,7 @@ 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) }
5
+ let(:content_hash) { '46cdc03462b9af57968df67b450cc4372ac41f53' }
5
6
 
6
7
  subject { described_class.new(content, filename) }
7
8
 
@@ -31,7 +32,6 @@ RSpec.describe Licensee::ProjectFiles::LicenseFile do
31
32
  end
32
33
 
33
34
  it 'creates the hash' do
34
- content_hash = 'd64f3bb4282a97b37454b5bb96a8a264a3363dc3'
35
35
  expect(subject.content_hash).to eql(content_hash)
36
36
  end
37
37
 
@@ -109,11 +109,11 @@ RSpec.describe Licensee::ProjectFiles::LicenseFile do
109
109
 
110
110
  context 'any extension regex' do
111
111
  it 'matches .foo' do
112
- expect(described_class::ANY_EXT_REGEX).to match('.foo')
112
+ expect(described_class::OTHER_EXT_REGEX).to match('.foo')
113
113
  end
114
114
 
115
115
  it 'does not match .md/foo' do
116
- expect(described_class::ANY_EXT_REGEX).to_not match('.md/foo')
116
+ expect(described_class::OTHER_EXT_REGEX).to_not match('.md/foo')
117
117
  end
118
118
  end
119
119
 
@@ -1,10 +1,15 @@
1
- [Licensee::Projects::FSProject,
2
- Licensee::Projects::GitProject].each do |project_type|
1
+ [
2
+ Licensee::Projects::FSProject,
3
+ Licensee::Projects::GitProject,
4
+ Licensee::Projects::GitHubProject
5
+ ].each do |project_type|
3
6
  RSpec.describe project_type do
7
+ let(:stubbed_org) { '_licensee_test_fixture' }
4
8
  let(:mit) { Licensee::License.find('mit') }
5
9
  let(:other) { Licensee::License.find('other') }
6
10
  let(:fixture) { 'mit' }
7
11
  let(:path) { fixture_path(fixture) }
12
+ let(:api_base) { 'https://api.github.com/repos' }
8
13
  subject { described_class.new(path) }
9
14
 
10
15
  if described_class == Licensee::Projects::GitProject
@@ -21,6 +26,26 @@
21
26
  subject.close
22
27
  FileUtils.rm_rf File.expand_path '.git', path
23
28
  end
29
+ elsif described_class == Licensee::Projects::GitHubProject
30
+ let(:path) do
31
+ stub_request(
32
+ :get, "#{api_base}/#{stubbed_org}/#{fixture}/contents/"
33
+ ).to_return(
34
+ status: 200,
35
+ body: fixture_root_contents_from_api(fixture),
36
+ headers: { 'Content-Type' => 'application/json' }
37
+ )
38
+
39
+ fixture_root_files(fixture).each do |file|
40
+ relative_path = File.basename(file)
41
+ parts = [api_base, stubbed_org, fixture, 'contents', relative_path]
42
+ stub_request(:get, parts.join('/'))
43
+ .with(headers: { 'accept' => 'application/vnd.github.v3.raw' })
44
+ .to_return(status: 200, body: File.read(file))
45
+ end
46
+
47
+ "https://github.com/#{stubbed_org}/#{fixture}"
48
+ end
24
49
  end
25
50
 
26
51
  if described_class == Licensee::Projects::GitProject
@@ -142,9 +167,11 @@
142
167
 
143
168
  # Using a `.gemspec` extension in the fixture breaks `gem release`
144
169
  before do
145
- FileUtils.cp("#{path}/project._gemspec", "#{path}/project.gemspec")
170
+ from = "#{fixture_path(fixture)}/project._gemspec"
171
+ to = "#{fixture_path(fixture)}/project.gemspec"
172
+ FileUtils.cp(from, to)
146
173
  if described_class == Licensee::Projects::GitProject
147
- Dir.chdir path do
174
+ Dir.chdir fixture_path(fixture) do
148
175
  `git add project.gemspec`
149
176
  `git commit -m 'add real gemspec'`
150
177
  end
@@ -152,7 +179,7 @@
152
179
  end
153
180
 
154
181
  after do
155
- FileUtils.rm("#{path}/project.gemspec")
182
+ FileUtils.rm("#{fixture_path(fixture)}/project.gemspec")
156
183
  end
157
184
 
158
185
  subject { described_class.new(path, detect_packages: true) }
@@ -0,0 +1,109 @@
1
+ RSpec.describe Licensee::Projects::GitHubProject do
2
+ let(:repo) { 'benbalter/licensee' }
3
+ let(:github_url) { "https://github.com/#{repo}" }
4
+ let(:mit) { Licensee::License.find('mit') }
5
+ let(:readme_file) { File.read(fixture_path('mit/README.md')) }
6
+ let(:license_file) { File.read(fixture_path('mit/LICENSE.txt')) }
7
+ subject(:instance) { described_class.new(github_url) }
8
+
9
+ describe '#initialize' do
10
+ context 'with a GitHub URI' do
11
+ it 'should set @repo' do
12
+ expect(instance.repo).to eq(repo)
13
+ end
14
+ end
15
+
16
+ context 'with a GitHub git URI' do
17
+ let(:github_url) { "https://github.com/#{repo}.git" }
18
+
19
+ it 'should set @repo, stripping the trailing extension' do
20
+ expect(instance.repo).to eq(repo)
21
+ end
22
+ end
23
+
24
+ context 'with a non-GitHub URI' do
25
+ let(:github_url) { "https://gitlab.com/#{repo}" }
26
+
27
+ it 'should raise an ArgumentError' do
28
+ expect { instance }.to raise_error(ArgumentError)
29
+ end
30
+ end
31
+
32
+ context 'with a local folder' do
33
+ let(:github_url) { fixture_path('mit') }
34
+
35
+ it 'should raise an ArgumentError' do
36
+ expect { instance }.to raise_error(ArgumentError)
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'when the repo exists' do
42
+ before do
43
+ stub_request(:get, 'https://api.github.com/repos/benbalter/licensee/contents/')
44
+ .to_return(
45
+ status: 200,
46
+ body: fixture_contents('webmock/licensee.json'),
47
+ headers: { 'Content-Type' => 'application/json' }
48
+ )
49
+
50
+ stub_request(:get, 'https://api.github.com/repos/benbalter/licensee/contents/LICENSE.txt')
51
+ .with(headers: { 'accept' => 'application/vnd.github.v3.raw' })
52
+ .to_return(status: 200, body: license_file)
53
+
54
+ stub_request(:get, 'https://api.github.com/repos/benbalter/licensee/contents/README.md')
55
+ .with(headers: { 'accept' => 'application/vnd.github.v3.raw' })
56
+ .to_return(status: 200, body: readme_file)
57
+ end
58
+
59
+ it 'returns the license' do
60
+ expect(subject.license).to be_a(Licensee::License)
61
+ expect(subject.license).to eql(mit)
62
+ end
63
+
64
+ it 'returns the matched file' do
65
+ expect(subject.matched_file).to be_a(Licensee::ProjectFiles::LicenseFile)
66
+ expect(subject.matched_file.filename).to eql('LICENSE.txt')
67
+ end
68
+
69
+ it 'returns the license file' do
70
+ expect(subject.license_file).to be_a(Licensee::ProjectFiles::LicenseFile)
71
+ expect(subject.license_file.filename).to eql('LICENSE.txt')
72
+ end
73
+
74
+ it "doesn't return the readme" do
75
+ expect(subject.readme_file).to be_nil
76
+ end
77
+
78
+ it "doesn't return the package file" do
79
+ expect(subject.package_file).to be_nil
80
+ end
81
+
82
+ context 'readme detection' do
83
+ subject { described_class.new(github_url, detect_readme: true) }
84
+
85
+ it 'returns the readme' do
86
+ expect(subject.readme_file).to be_a(Licensee::ProjectFiles::ReadmeFile)
87
+ expect(subject.readme_file.filename).to eql('README.md')
88
+ end
89
+
90
+ it 'returns the license' do
91
+ expect(subject.license).to be_a(Licensee::License)
92
+ expect(subject.license).to eql(mit)
93
+ end
94
+ end
95
+ end
96
+
97
+ context 'when the repo cannot be found' do
98
+ let(:repo) { 'benbalter/not-foundsss' }
99
+
100
+ before do
101
+ stub_request(:get, 'https://api.github.com/repos/benbalter/not-foundsss/contents/')
102
+ .to_return(status: 404)
103
+ end
104
+
105
+ it 'raises a RepoNotFound error' do
106
+ expect { subject.license }.to raise_error(described_class::RepoNotFound)
107
+ end
108
+ end
109
+ end
@@ -2,7 +2,7 @@ RSpec.describe Licensee do
2
2
  let(:project_path) { fixture_path('mit') }
3
3
  let(:license_path) { fixture_path('mit/LICENSE.txt') }
4
4
  let(:mit_license) { Licensee::License.find('mit') }
5
- let(:hidden_license_count) { 33 }
5
+ let(:hidden_license_count) { 34 }
6
6
 
7
7
  it 'exposes licenses' do
8
8
  expect(described_class.licenses).to be_an(Array)
@@ -19,8 +19,20 @@ RSpec.describe Licensee do
19
19
  expect(Licensee.license(license_path)).to eql(mit_license)
20
20
  end
21
21
 
22
- it 'inits a project' do
23
- expect(Licensee.project(project_path)).to be_a(Licensee::Projects::Project)
22
+ describe '.project' do
23
+ subject { Licensee.project(project_path) }
24
+
25
+ it 'inits a project' do
26
+ expect(subject).to be_a(Licensee::Projects::Project)
27
+ end
28
+
29
+ context 'given a GitHub repository' do
30
+ let(:project_path) { 'https://github.com/benbalter/licensee' }
31
+
32
+ it 'creates a GitHubProject' do
33
+ expect(subject).to be_a(Licensee::Projects::GitHubProject)
34
+ end
35
+ end
24
36
  end
25
37
 
26
38
  context 'confidence threshold' do
@@ -6,6 +6,9 @@ require 'open3'
6
6
  require 'tmpdir'
7
7
  require 'mustache'
8
8
 
9
+ require 'webmock/rspec'
10
+ WebMock.disable_net_connect!
11
+
9
12
  RSpec.configure do |config|
10
13
  config.shared_context_metadata_behavior = :apply_to_host_groups
11
14
  config.example_status_persistence_file_path = 'spec/examples.txt'
@@ -30,6 +33,23 @@ def fixture_path(fixture)
30
33
  File.expand_path fixture, fixtures_base
31
34
  end
32
35
 
36
+ def fixture_contents(fixture)
37
+ File.read fixture_path(fixture)
38
+ end
39
+
40
+ def fixture_root_files(fixture)
41
+ Dir["#{fixture_path(fixture)}/*"]
42
+ end
43
+
44
+ def fixture_root_contents_from_api(fixture)
45
+ fixture_root_files(fixture).map do |file|
46
+ {
47
+ name: File.basename(file),
48
+ type: 'file'
49
+ }
50
+ end.to_json
51
+ end
52
+
33
53
  def sub_copyright_info(license)
34
54
  Mustache.render license.content_for_mustache, fullname: 'Ben Balter',
35
55
  year: '2016',