licensee 8.5.0 → 8.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -104
  3. data/bin/licensee +26 -12
  4. data/lib/licensee.rb +1 -0
  5. data/lib/licensee/license.rb +6 -2
  6. data/lib/licensee/matchers/copyright_matcher.rb +2 -0
  7. data/lib/licensee/matchers/cran_matcher.rb +20 -0
  8. data/lib/licensee/matchers/exact_matcher.rb +2 -0
  9. data/lib/licensee/project.rb +2 -1
  10. data/lib/licensee/project_file.rb +8 -2
  11. data/lib/licensee/project_files/license_file.rb +27 -6
  12. data/lib/licensee/project_files/package_info.rb +6 -1
  13. data/lib/licensee/project_files/readme.rb +2 -2
  14. data/lib/licensee/projects/fs_project.rb +0 -1
  15. data/lib/licensee/version.rb +1 -1
  16. data/spec/bin_spec.rb +56 -0
  17. data/spec/fixtures/case-sensitive/LiCeNsE.TxT +0 -0
  18. data/spec/fixtures/gemspec/project.gemspec +1 -0
  19. data/spec/fixtures/lgpl/COPYING.lesser +165 -0
  20. data/spec/fixtures/lgpl/LICENSE +674 -0
  21. data/spec/fixtures/license-folder/README.md +0 -0
  22. data/{test/fixtures/mit-without-title/mit.txt → spec/fixtures/mit/LICENSE.txt} +3 -1
  23. data/{test/fixtures/mit-with-redundant-title/mit.txt → spec/fixtures/mit/README.md} +4 -2
  24. data/spec/fixtures/mpl-without-hrs/LICENSE +362 -0
  25. data/spec/fixtures/readme/README.md +23 -0
  26. data/spec/integration_spec.rb +121 -0
  27. data/spec/licensee/content_helper_spec.rb +77 -0
  28. data/spec/licensee/license_spec.rb +224 -0
  29. data/spec/licensee/matchers/copyright_matcher_spec.rb +47 -0
  30. data/spec/licensee/matchers/cran_matcher_spec.rb +18 -0
  31. data/spec/licensee/matchers/dice_matcher_spec.rb +43 -0
  32. data/spec/licensee/matchers/exact_matcher_spec.rb +26 -0
  33. data/spec/licensee/matchers/gemspec_matcher_spec.rb +29 -0
  34. data/spec/licensee/matchers/npm_bower_matcher_spec.rb +31 -0
  35. data/spec/licensee/matchers/package_matcher_spec.rb +15 -0
  36. data/spec/licensee/project_files/license_file_spec.rb +122 -0
  37. data/spec/licensee/project_files/package_info_spec.rb +51 -0
  38. data/spec/licensee/project_files/readme_spec.rb +77 -0
  39. data/spec/licensee/project_spec.rb +91 -0
  40. data/spec/licensee_spec.rb +41 -0
  41. data/spec/project_file_spec.rb +33 -0
  42. data/spec/spec_helper.rb +78 -0
  43. data/spec/vendored_license_spec.rb +75 -0
  44. data/vendor/choosealicense.com/_licenses/bsl-1.0.txt +48 -0
  45. data/vendor/choosealicense.com/_licenses/lgpl-3.0.txt +1 -1
  46. metadata +39 -111
  47. data/Rakefile +0 -12
  48. data/test/fixtures/apache-2.0/LICENSE +0 -201
  49. data/test/fixtures/bower-with-readme/README.md +0 -1
  50. data/test/fixtures/bower-with-readme/bower.json +0 -3
  51. data/test/fixtures/bower/bower.json +0 -3
  52. data/test/fixtures/bsd-2-clause-without-title/bsd-2-clause.txt +0 -23
  53. data/test/fixtures/bsd-3-clause-without-title/bsd-3-clause.txt +0 -27
  54. data/test/fixtures/case-sensitive.git/HEAD +0 -1
  55. data/test/fixtures/case-sensitive.git/config +0 -6
  56. data/test/fixtures/case-sensitive.git/objects/01/7b4f1eebd1dcb735e950b1d01093e3e2bf85e9 +0 -0
  57. data/test/fixtures/case-sensitive.git/objects/2c/b878e0851c5cf53d7455d9018baa6755a38bd7 +0 -0
  58. data/test/fixtures/case-sensitive.git/objects/fb/ddf40ba5f30225af7cd9841afe374ca5800cb9 +0 -0
  59. data/test/fixtures/case-sensitive.git/refs/heads/master +0 -1
  60. data/test/fixtures/isc-without-title/isc.txt +0 -13
  61. data/test/fixtures/lgpl.git/HEAD +0 -1
  62. data/test/fixtures/lgpl.git/config +0 -5
  63. data/test/fixtures/lgpl.git/objects/1a/cd060ebbbeac294200008657d9502130f93465 +0 -2
  64. data/test/fixtures/lgpl.git/objects/4b/1f98c1e95b6d4dae0b0a160f554be97e5afece +0 -2
  65. data/test/fixtures/lgpl.git/objects/a4/cfa42bc8e1d432fa851c5c4e3f294f01e05fd3 +0 -0
  66. data/test/fixtures/lgpl.git/objects/b7/de6e186bd02935030f5d42867ea7043fb1c27c +0 -0
  67. data/test/fixtures/lgpl.git/objects/dd/d0e017b1bf39218a6ea4f2fadd29a7ea8ebe03 +0 -0
  68. data/test/fixtures/lgpl.git/objects/eb/d853e83a2d317422c52f3922f4c9c5bb4a10b7 +0 -0
  69. data/test/fixtures/lgpl.git/refs/heads/master +0 -1
  70. data/test/fixtures/licence.git/HEAD +0 -1
  71. data/test/fixtures/licence.git/config +0 -6
  72. data/test/fixtures/licence.git/objects/66/0c086dc25f9f3b96e7afd9dee8a11b4e614543 +0 -0
  73. data/test/fixtures/licence.git/objects/68/804815597f79aa323de3257a8fd7b76449943c +0 -0
  74. data/test/fixtures/licence.git/objects/dd/59aed84c5aa4dff7ceda11a1c045f831194067 +0 -0
  75. data/test/fixtures/licence.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  76. data/test/fixtures/licence.git/refs/heads/master +0 -1
  77. data/test/fixtures/license-folder.git/HEAD +0 -1
  78. data/test/fixtures/license-folder.git/config +0 -6
  79. data/test/fixtures/license-folder.git/objects/32/6d0761f0c54d54327ea9e127e02d9bae14d2c8 +0 -2
  80. data/test/fixtures/license-folder.git/objects/93/109217bbe2937fc3a8d8933fddd80ed6292481 +0 -0
  81. data/test/fixtures/license-folder.git/objects/c6/6e45436e4f3fda934dc7268bccbc59c37a67b4 +0 -0
  82. data/test/fixtures/license-folder.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  83. data/test/fixtures/license-folder.git/refs/heads/master +0 -1
  84. data/test/fixtures/licenses.git/HEAD +0 -1
  85. data/test/fixtures/licenses.git/config +0 -4
  86. data/test/fixtures/licenses.git/objects/51/a11d50f29a14774ded8f7b90ba9938dce78a92 +0 -3
  87. data/test/fixtures/licenses.git/objects/5e/df454e6517673d5e64a33cf284308b9c6b1075 +0 -0
  88. data/test/fixtures/licenses.git/objects/e1/b4dc13f4bf683ce8f2943e051c3e91e778d043 +0 -0
  89. data/test/fixtures/licenses.git/objects/info/packs +0 -2
  90. data/test/fixtures/licenses.git/objects/pack/pack-4a7088171ae3ca900f010a4be6f1c2c96490c338.idx +0 -0
  91. data/test/fixtures/licenses.git/objects/pack/pack-4a7088171ae3ca900f010a4be6f1c2c96490c338.pack +0 -0
  92. data/test/fixtures/licenses.git/packed-refs +0 -4
  93. data/test/fixtures/licenses.git/refs/heads/master +0 -1
  94. data/test/fixtures/mit-without-title-rewrapped/mit.txt +0 -19
  95. data/test/fixtures/mpl-without-hrs.git/HEAD +0 -1
  96. data/test/fixtures/mpl-without-hrs.git/config +0 -5
  97. data/test/fixtures/mpl-without-hrs.git/objects/45/26aa2d1d78ea20fb0faf59f2360a68fa897774 +0 -0
  98. data/test/fixtures/mpl-without-hrs.git/objects/ba/f5649b61fac4ed64ec2949fe5cd616b85a8298 +0 -0
  99. data/test/fixtures/mpl-without-hrs.git/objects/be/2cc4dfb609fb6c38f6365ec345bded3350dd63 +0 -0
  100. data/test/fixtures/mpl-without-hrs.git/refs/heads/master +0 -1
  101. data/test/fixtures/named-license-file-prefix.git/HEAD +0 -1
  102. data/test/fixtures/named-license-file-prefix.git/config +0 -6
  103. data/test/fixtures/named-license-file-prefix.git/objects/64/3983d3f82ecc2a7d8e4227946220ebffd477d2 +0 -4
  104. data/test/fixtures/named-license-file-prefix.git/objects/c9/b229e500e529fdbd4f50746ba207e91d0677b6 +0 -7
  105. data/test/fixtures/named-license-file-prefix.git/objects/d1/9223f355283b3ce0c51a2c527f685d0f403157 +0 -0
  106. data/test/fixtures/named-license-file-prefix.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  107. data/test/fixtures/named-license-file-prefix.git/refs/heads/master +0 -1
  108. data/test/fixtures/named-license-file-suffix.git/HEAD +0 -1
  109. data/test/fixtures/named-license-file-suffix.git/config +0 -6
  110. data/test/fixtures/named-license-file-suffix.git/objects/36/465372136f81a2089f486298ca77ef41611198 +0 -0
  111. data/test/fixtures/named-license-file-suffix.git/objects/4a/2a139e7fbd24eef5c5ef3d22f490e89405f6a3 +0 -3
  112. data/test/fixtures/named-license-file-suffix.git/objects/c9/b229e500e529fdbd4f50746ba207e91d0677b6 +0 -7
  113. data/test/fixtures/named-license-file-suffix.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  114. data/test/fixtures/named-license-file-suffix.git/refs/heads/master +0 -1
  115. data/test/fixtures/no-license.git/HEAD +0 -1
  116. data/test/fixtures/no-license.git/config +0 -6
  117. data/test/fixtures/no-license.git/objects/82/0c999cf27a6f71431646c404274c578f7a2869 +0 -0
  118. data/test/fixtures/no-license.git/objects/e1/d9b2a3d41c2ea74a520e66da2b5c63b2f6202f +0 -0
  119. data/test/fixtures/no-license.git/objects/ff/1592f44259635df9feda5e02853964b26f9e4d +0 -0
  120. data/test/fixtures/no-license.git/refs/heads/master +0 -1
  121. data/test/fixtures/npm-non-spdx/package.json +0 -3
  122. data/test/fixtures/npm.git/HEAD +0 -1
  123. data/test/fixtures/npm.git/config +0 -4
  124. data/test/fixtures/npm.git/objects/info/packs +0 -2
  125. data/test/fixtures/npm.git/objects/pack/pack-03c0879445cabcc37f91d97c7955465adef26f4a.idx +0 -0
  126. data/test/fixtures/npm.git/objects/pack/pack-03c0879445cabcc37f91d97c7955465adef26f4a.pack +0 -0
  127. data/test/fixtures/npm.git/packed-refs +0 -2
  128. data/test/fixtures/npm/package.json +0 -3
  129. data/test/functions.rb +0 -73
  130. data/test/helper.rb +0 -16
  131. data/test/licensee/matchers/test_copyright_matcher.rb +0 -59
  132. data/test/licensee/matchers/test_dice_matcher.rb +0 -60
  133. data/test/licensee/matchers/test_exact_matcher.rb +0 -25
  134. data/test/licensee/matchers/test_gemspec_matcher.rb +0 -11
  135. data/test/licensee/matchers/test_npm_bower_matcher.rb +0 -27
  136. data/test/licensee/matchers/test_package_matcher.rb +0 -27
  137. data/test/licensee/project_files/test_license_file.rb +0 -73
  138. data/test/licensee/project_files/test_package_info.rb +0 -19
  139. data/test/licensee/project_files/test_readme.rb +0 -47
  140. data/test/licensee/test_content_helper.rb +0 -81
  141. data/test/licensee/test_license.rb +0 -182
  142. data/test/licensee/test_project.rb +0 -134
  143. data/test/licensee/test_project_file.rb +0 -24
  144. data/test/test_licensee.rb +0 -40
  145. data/test/test_licensee_bin.rb +0 -37
  146. data/test/test_licensee_vendor.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: '09da33c25905df581cb047d1eed3c138ede5f440'
4
- data.tar.gz: c0d34f622f3f6dde90f32c859b221b6b4af02bce
3
+ metadata.gz: a09cefedc079e0510fbdae2de030984fc477a60b
4
+ data.tar.gz: 1648fed5fcbab4086f7f2d992ee9fea4b03fbe01
5
5
  SHA512:
6
- metadata.gz: 0c253e00b53aa258a70e80fad5a94454ff9ae080d9911f20e999e09eba9db14b306052dbf04b0e66de8ae2256ee87d81b4d458e4fa5317bd84e129bfe5ef2084
7
- data.tar.gz: 7d0e97bbc08a7d687b6011690e8d346d76f97a6c1d9ac5ee2cede3400771c480c05950e904f5f632d01ff0bed0e699233cb3961f8e79f75ed4a91b7265fbac2c
6
+ metadata.gz: 64bb0bb0ccbe7bb4df9d043182ab3b2a598544b2c42212b2489d448b821d170ce7c48aaf9213a56c407f72e061d81710be4b07b7de9efffd226e8940e4c98fd2
7
+ data.tar.gz: 42f5c17fdb81239632a12e41df5c4e66cb8b29600eb23a3674a75f9b51a0aec3961a400edff62430bea76ebd400deac50e344ca59ba7856504d52bc30b58cc50
data/README.md CHANGED
@@ -1,24 +1,38 @@
1
1
  # Licensee
2
- _A Ruby Gem to detect under what license a project is distributed._
3
2
 
4
- [![Build Status](https://travis-ci.org/benbalter/licensee.svg?branch=master)](https://travis-ci.org/benbalter/licensee) [![Gem Version](https://badge.fury.io/rb/licensee.svg)](http://badge.fury.io/rb/licensee)
3
+ *A Ruby Gem to detect under what license a project is distributed.*
4
+
5
+ [![Build Status](https://travis-ci.org/benbalter/licensee.svg?branch=master)](https://travis-ci.org/benbalter/licensee) [![Gem Version](https://badge.fury.io/rb/licensee.svg)](http://badge.fury.io/rb/licensee) [![Coverage Status](https://coveralls.io/repos/github/benbalter/licensee/badge.svg?branch=rspec)](https://coveralls.io/github/benbalter/licensee?branch=rspec)
5
6
 
6
7
  ## The problem
7
- - You've got an open source project. How do you know what you can and can't do with the software?
8
- - You've got a bunch of open source projects, how do you know what their licenses are?
9
- - You've got a project with a license file, but which license is it? Has it been modified?
8
+
9
+ * You've got an open source project. How do you know what you can and can't do with the software?
10
+ * You've got a bunch of open source projects, how do you know what their licenses are?
11
+ * You've got a project with a license file, but which license is it? Has it been modified?
10
12
 
11
13
  ## The solution
14
+
12
15
  Licensee automates the process of reading `LICENSE` files and compares their contents to known licenses using a several strategies (which we call "Matchers"). It attempts to determine a project's license in the following order:
13
- - If the license file has an explicit copyright notice, and nothing more (e.g., `Copyright (c) 2015 Ben Balter`), we'll assume the author intends to retain all rights, and thus the project isn't licensed.
14
- - If the license is an exact match to a known license. If we strip away whitespace and copyright notice, we might get lucky, and direct string comparison in Ruby is cheap.
15
- - If we still can't match the license, we use a fancy math thing called the [Sørensen–Dice coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient), which is really good at calculating the similarity between two strings. By calculating the percent changed from the known license to the license file, you can tell, e.g., that a given license is 90% similar to the MIT license, that 10% likely representing the copyright line being properly adapted to the project.
16
16
 
17
- _Special thanks to [@vmg](https://github.com/vmg) for his Git and algorithmic prowess._
17
+ * If the license file has an explicit copyright notice, and nothing more (e.g., `Copyright (c) 2015 Ben Balter`), we'll assume the author intends to retain all rights, and thus the project isn't licensed.
18
+ * If the license is an exact match to a known license. If we strip away whitespace and copyright notice, we might get lucky, and direct string comparison in Ruby is cheap.
19
+ * If we still can't match the license, we use a fancy math thing called the [Sørensen–Dice coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient), which is really good at calculating the similarity between two strings. By calculating the percent changed from the known license to the license file, you can tell, e.g., that a given license is 95% similar to the MIT license, that 5% likely representing legally insignificant changes to the license text.
20
+
21
+ *Special thanks to [@vmg](https://github.com/vmg) for his Git and algorithmic prowess.*
18
22
 
19
23
  ## Installation
24
+
20
25
  `gem install licensee` or add `gem 'licensee'` to your project's `Gemfile`.
21
26
 
27
+ ## Documentation
28
+
29
+ See [the docs folder](/docs) for more information. You may be interested in:
30
+
31
+ * [Contributing to Licensee](CONTRIBUTING.md) (and development instructions)
32
+ * [Customizing Licensee's behavior](docs/customizing.md)
33
+ * [Instructions for using Licensee](docs/usage.md)
34
+ * More information about [what Licensee looks at](docs/what-we-look-at.md) (or doesn't, and why)
35
+
22
36
  ## Semantic Versioning
23
37
 
24
38
  This project conforms to [semver](http://semver.org/). As a result of this policy, you can (and should) specify a dependency on this gem using the [Pessimistic Version Constraint](http://guides.rubygems.org/patterns/) with two digits of precision. For example:
@@ -28,98 +42,3 @@ spec.add_dependency 'licensee', '~> 1.0'
28
42
  This means your project is compatible with licensee 1.0 up until 2.0. You can also set a higher minimum version:
29
43
 
30
44
  spec.add_dependency 'licensee', '~> 1.1'
31
-
32
- ## Command line usage
33
- 1. `cd` into a project directory
34
- 2. execute the `licensee` command
35
-
36
- You'll get an output that looks like:
37
-
38
- ```
39
- License: MIT
40
- Confidence: 98.42%
41
- Matcher: Licensee::GitMatcher
42
- ```
43
-
44
- Alternately, `licensee <directory>` will treat the argument as the project directory, and `licensee <file>` will attempt to match the individual file specified, both with output that looks like the above.
45
-
46
- ## License API
47
-
48
- ```ruby
49
- license = Licensee.license "/path/to/a/project"
50
- => #<Licensee::License name="MIT" match=0.9842154131847726>
51
-
52
- license.key
53
- => "mit"
54
-
55
- license.name
56
- => "MIT License"
57
-
58
- license.meta["source"]
59
- => "http://opensource.org/licenses/MIT"
60
-
61
- license.meta["description"]
62
- => "A permissive license that is short and to the point. It lets people do anything with your code with proper attribution and without warranty."
63
-
64
- license.meta["permissions"]
65
- => ["commercial-use","modifications","distribution","private-use"]
66
- ```
67
-
68
- ## More API
69
- You can gather more information by working with the project object, and the top level Licensee class.
70
-
71
- ```ruby
72
- Licensee::VERSION # The Licensee version
73
- Licensee.licenses # All the licenses Licensee knows about
74
-
75
- project=Licensee.project "/path/to/a/project" # Get a Project (Git checkout or just local Filesystem) (post 6.0.0)
76
-
77
- project.license # The matched license
78
- project.matched_file # Object for the particular file containing the apparent license
79
- project.matched_file.filename # Its filename
80
- project.matched_file.confidence # The confidence level in the license matching
81
- project.matched_file.content # The content of your license file
82
- project.license.content # The Open Source License text it matched against
83
- ```
84
-
85
- ## What it looks at
86
- - `LICENSE`, `LICENSE.txt`, `COPYING`, etc. files in the root of the project, comparing the body to known licenses
87
- - Crowdsourced license content and metadata from [`choosealicense.com`](http://choosealicense.com)
88
-
89
- ## What it doesn't look at
90
- - Dependency licensing
91
- - References to licenses in `README`, `README.md`, etc.
92
- - Every single possible license (just the most popular ones)
93
- - Compliance (e.g., whitelisting certain licenses)
94
-
95
- If you're looking for dependency license checking and compliance, take a look at [LicenseFinder](https://github.com/pivotal/LicenseFinder).
96
-
97
- ## Huh? Why don't you look at X?
98
- Because reasons.
99
-
100
- ### Why not just look at the "license" field of [insert package manager here]?
101
- Because it's not legally binding. A license is a legal contract. You give up certain rights (e.g., the right to sue the author) in exchange for the right to use the software.
102
-
103
- Most popular licenses today _require_ that the license itself be distributed along side the software. Simply putting the letters "MIT" or "GPL" in a configuration file doesn't really meet that requirement.
104
-
105
- Not to mention, it doesn't tell you much about your rights as a user. Is it GPLv2? GPLv2 or later? Those files are designed to be read by computers (who can't enter into contracts), not humans (who can). It's great metadata, but that's about it.
106
-
107
- ### What about looking to see if the author said something in the readme?
108
- You could make an argument that, when linked or sufficiently identified, the terms of the license are incorporated by reference, or at least that the author's intent is there. There's a handful of reasons why this isn't ideal. For one, if you're using the MIT or BSD (ISC) license, along with a few others, there's templematic language, like the copyright notice, which would go unfilled.
109
-
110
- ### What about checking every single file for a copyright header?
111
- Because that's silly in the context of how software is developed today. You wouldn't put a copyright notice on each page of a book. Besides, it's a lot of work, as there's no standardized, cross-platform way to describe a project's license within a comment.
112
-
113
- Checking the actual text into version control is definitive, so that's what this project looks at.
114
-
115
- ## Bootstrapping a local development environment
116
- `script/bootstrap`
117
-
118
- ## Running tests
119
- `script/cibuild`
120
-
121
- ## Updating the licenses
122
- License data is pulled from `choosealicense.com`. To update the license data, simple run `script/vendor-licenses`.
123
-
124
- ## Roadmap
125
- See [proposed enhancements](https://github.com/benbalter/licensee/labels/enhancement).
@@ -14,23 +14,37 @@ matched_file = project.matched_file
14
14
 
15
15
  if license_file
16
16
  puts "License file: #{license_file.filename}"
17
+ puts "License hash: #{license_file.hash}"
17
18
  puts "Attribution: #{license_file.attribution}" if license_file.attribution
18
19
  end
19
20
 
20
- if matched_file
21
- if matched_file.license
22
- puts "License: #{matched_file.license.meta['title']}"
23
- puts "Confidence: #{format_percent(matched_file.confidence)}" if matched_file.confidence
24
- puts "Method: #{matched_file.matcher.class}" if matched_file.matcher
25
- else
26
- puts 'License: Not detected'
21
+ unless matched_file
22
+ puts 'License: Not detected'
23
+ exit 1
24
+ end
25
+
26
+ if matched_file.license
27
+ puts "License: #{matched_file.license.meta['title']}"
28
+
29
+ if matched_file.confidence
30
+ puts "Confidence: #{format_percent(matched_file.confidence)}"
31
+ end
32
+
33
+ puts "Method: #{matched_file.matcher.class}" if matched_file.matcher
34
+ exit 0
35
+ end
36
+
37
+ if matched_file.is_a?(Licensee::Project::LicenseFile)
38
+ matcher = Licensee::Matchers::Dice.new(matched_file)
39
+ licenses = matcher.licenses_by_similiarity
40
+ unless licenses.empty?
27
41
  puts
28
42
  puts "Here's the closest licenses:"
29
- matcher = Licensee::Matchers::Dice.new(matched_file)
30
- matcher.licenses_by_similiarity[0...3].each do |license, similarity|
31
- puts "* #{license.meta['spdx-id']} similarity: #{format_percent(similarity)}"
43
+ licenses[0...3].each do |license, similarity|
44
+ spdx_id = license.meta['spdx-id']
45
+ puts "* #{spdx_id} similarity: #{format_percent(similarity)}"
32
46
  end
33
47
  end
34
- else
35
- puts 'Unknown'
36
48
  end
49
+
50
+ exit 1
@@ -20,6 +20,7 @@ require_relative 'licensee/matchers/dice_matcher'
20
20
  require_relative 'licensee/matchers/package_matcher'
21
21
  require_relative 'licensee/matchers/gemspec_matcher'
22
22
  require_relative 'licensee/matchers/npm_bower_matcher'
23
+ require_relative 'licensee/matchers/cran_matcher'
23
24
 
24
25
  module Licensee
25
26
  # Over which percent is a match considered a match by default
@@ -131,12 +131,16 @@ module Licensee
131
131
  !other.nil? && key == other.key
132
132
  end
133
133
 
134
- private
135
-
136
134
  def pseudo_license?
137
135
  PSEUDO_LICENSES.include?(key)
138
136
  end
139
137
 
138
+ def inspect
139
+ "#<Licensee::License key=#{key}>"
140
+ end
141
+
142
+ private
143
+
140
144
  # Raw content of license file, including YAML front matter
141
145
  def raw_content
142
146
  return if pseudo_license?
@@ -2,6 +2,8 @@
2
2
  module Licensee
3
3
  module Matchers
4
4
  class Copyright
5
+ attr_reader :file
6
+
5
7
  # rubocop:disable Metrics/LineLength
6
8
  REGEX = /\s*(Copyright|\(c\)) (©|\(c\)|\xC2\xA9)? ?(\d{4}|\[year\])(.*)?\s*/i
7
9
 
@@ -0,0 +1,20 @@
1
+ module Licensee
2
+ module Matchers
3
+ class Cran < Package
4
+ attr_reader :file
5
+
6
+ # While we could parse the package.json or bower.json file, prefer
7
+ # a lenient regex for speed and security. Moar parsing moar problems.
8
+ LICENSE_REGEX = /
9
+ ^license:\s*([a-z\-0-9\.]+)
10
+ /ix
11
+
12
+ private
13
+
14
+ def license_property
15
+ match = @file.content.match LICENSE_REGEX
16
+ match[1].downcase if match && match[1]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,8 @@
1
1
  module Licensee
2
2
  module Matchers
3
3
  class Exact
4
+ attr_reader :file
5
+
4
6
  def initialize(file)
5
7
  @file = file
6
8
  end
@@ -36,7 +36,7 @@ module Licensee
36
36
  end
37
37
  end
38
38
 
39
- def readme
39
+ def readme_file
40
40
  return unless detect_readme?
41
41
  return @readme if defined? @readme
42
42
  @readme = begin
@@ -45,6 +45,7 @@ module Licensee
45
45
  Readme.new(content, name) if content && name
46
46
  end
47
47
  end
48
+ alias readme readme_file
48
49
 
49
50
  def package_file
50
51
  return unless detect_packages?
@@ -3,10 +3,16 @@ module Licensee
3
3
  class File
4
4
  attr_reader :content, :filename
5
5
 
6
+ ENCODING = Encoding::UTF_8
7
+ ENCODING_OPTIONS = {
8
+ invalid: :replace,
9
+ undef: :replace,
10
+ replace: ''
11
+ }.freeze
12
+
6
13
  def initialize(content, filename = nil)
7
14
  @content = content
8
- options = { invalid: :replace, undef: :replace, replace: '' }
9
- @content.encode!(Encoding::UTF_8, options)
15
+ @content.encode!(ENCODING, ENCODING_OPTIONS)
10
16
  @filename = filename
11
17
  end
12
18
 
@@ -3,6 +3,32 @@ module Licensee
3
3
  class LicenseFile < Licensee::Project::File
4
4
  include Licensee::ContentHelper
5
5
 
6
+ # List of extensions to give preference to
7
+ PREFERRED_EXT = %w(md markdown txt).freeze
8
+ PREFERRED_EXT_REGEX = /\.#{Regexp.union(PREFERRED_EXT)}\z/
9
+
10
+ # Regex to match any extension
11
+ ANY_EXT_REGEX = %r{\.[^./]+\z}
12
+
13
+ # Regex to match, LICENSE, LICENCE, unlicense, etc.
14
+ LICENSE_REGEX = /(un)?licen[sc]e/i
15
+
16
+ # Regex to match COPYING, COPYRIGHT, etc.
17
+ COPYING_REGEX = /copy(ing|right)/i
18
+
19
+ # Hash of Regex => score with which to score potential license files
20
+ FILENAME_REGEXES = {
21
+ /\A#{LICENSE_REGEX}\z/ => 1.0, # LICENSE
22
+ /\A#{LICENSE_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.9, # LICENSE.md
23
+ /\A#{COPYING_REGEX}\z/ => 0.8, # COPYING
24
+ /\A#{COPYING_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.7, # COPYING.md
25
+ /\A#{LICENSE_REGEX}#{ANY_EXT_REGEX}\z/ => 0.6, # LICENSE.textile
26
+ /\A#{COPYING_REGEX}#{ANY_EXT_REGEX}\z/ => 0.5, # COPYING.textile
27
+ /#{LICENSE_REGEX}/ => 0.4, # LICENSE-MIT
28
+ /#{COPYING_REGEX}/ => 0.3, # COPYING-MIT
29
+ // => 0.0 # Catch all
30
+ }.freeze
31
+
6
32
  def possible_matchers
7
33
  [Matchers::Copyright, Matchers::Exact, Matchers::Dice]
8
34
  end
@@ -13,12 +39,7 @@ module Licensee
13
39
  end
14
40
 
15
41
  def self.name_score(filename)
16
- return 1.0 if filename =~ /\A(un)?licen[sc]e\z/i
17
- return 0.9 if filename =~ /\A(un)?licen[sc]e\.(md|markdown|txt)\z/i
18
- return 0.8 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
19
- return 0.7 if filename =~ /\A(un)?licen[sc]e\.[^.]+\z/i
20
- return 0.5 if filename =~ /licen[sc]e/i
21
- 0.0
42
+ FILENAME_REGEXES.find { |regex, _| filename =~ regex }[1]
22
43
  end
23
44
 
24
45
  # case-insensitive block to determine if the given file is LICENSE.lesser
@@ -8,13 +8,18 @@ module Licensee
8
8
  when '.json'
9
9
  [Matchers::NpmBower]
10
10
  else
11
- []
11
+ if filename == 'DESCRIPTION' && content.start_with?('Package:')
12
+ [Matchers::Cran]
13
+ else
14
+ []
15
+ end
12
16
  end
13
17
  end
14
18
 
15
19
  def self.name_score(filename)
16
20
  return 1.0 if ::File.extname(filename) == '.gemspec'
17
21
  return 1.0 if filename == 'package.json'
22
+ return 0.9 if filename == 'DESCRIPTION'
18
23
  return 0.75 if filename == 'bower.json'
19
24
  0.0
20
25
  end
@@ -2,8 +2,8 @@ module Licensee
2
2
  class Project
3
3
  class Readme < LicenseFile
4
4
  SCORES = {
5
- /\AREADME\z/i => 1.0,
6
- /\AREADME\.(md|markdown|txt)\z/i => 0.9
5
+ /\AREADME\z/i => 1.0,
6
+ /\AREADME\.(md|markdown|mdown|txt)\z/i => 0.9
7
7
  }.freeze
8
8
 
9
9
  CONTENT_REGEX = /^#+ Licen[sc]e$(.*?)(?=#+|\z)/im
@@ -35,7 +35,6 @@ module Licensee
35
35
  # Retrieve a file's content from disk
36
36
  #
37
37
  # file - the file hash, with the :name key as the file's relative path
38
- # path - the base path to the project
39
38
  #
40
39
  # Returns the fiel contents as a string
41
40
  def load_file(file)
@@ -1,3 +1,3 @@
1
1
  module Licensee
2
- VERSION = '8.5.0'.freeze
2
+ VERSION = '8.6.0'.freeze
3
3
  end
@@ -0,0 +1,56 @@
1
+ RSpec.describe 'command line invocation' do
2
+ let(:command) { ['ruby', 'bin/licensee'] }
3
+ let(:output) do
4
+ Dir.chdir project_root do
5
+ Open3.capture3(*[command, arguments].flatten)
6
+ end
7
+ end
8
+ let(:stdout) { output[0] }
9
+ let(:stderr) { output[1] }
10
+ let(:status) { output[2] }
11
+
12
+ context 'without any arguments' do
13
+ let(:arguments) { [] }
14
+
15
+ it 'Returns a zero exit code' do
16
+ expect(status.exitstatus).to eql(0)
17
+ end
18
+
19
+ it "detects the folder's license" do
20
+ expect(stdout).to match('License: MIT License')
21
+ end
22
+
23
+ it 'outputs the hash' do
24
+ expect(stdout).to match('750260c322080bab4c19fd55eb78bc73e1ae8f11')
25
+ end
26
+
27
+ it 'outputs the attribution' do
28
+ expect(stdout).to match('2014-2016 Ben Balter')
29
+ end
30
+
31
+ it 'outputs the confidence' do
32
+ expect(stdout).to match('Confidence: 100.00%')
33
+ end
34
+
35
+ it 'outputs the method' do
36
+ expect(stdout).to match('Method: Licensee::Matchers::Exact')
37
+ end
38
+ end
39
+
40
+ context 'when given a folder path' do
41
+ let(:arguments) { [project_root] }
42
+
43
+ it "detects the folder's license" do
44
+ expect(stdout).to match('License: MIT License')
45
+ end
46
+ end
47
+
48
+ context 'when given a license path' do
49
+ let(:license_path) { File.expand_path 'LICENSE.md', project_root }
50
+ let(:arguments) { [license_path] }
51
+
52
+ it "detects the file's license" do
53
+ expect(stdout).to match('License: MIT License')
54
+ end
55
+ end
56
+ end