licensee 9.6.0 → 9.7.0

Sign up to get free protection for your applications and to get access to all the features.
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',