license_finder 1.0.0.1 → 1.0.1
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.
- data/CHANGELOG.rdoc +21 -1
- data/features/configure_ignore_dependencies.feature +16 -0
- data/features/step_definitions/cli_steps.rb +1 -1
- data/features/step_definitions/configure_ignore_dependencies.rb +35 -0
- data/files/license_finder.yml +2 -0
- data/lib/license_finder/cli.rb +72 -30
- data/lib/license_finder/configuration.rb +17 -1
- data/lib/license_finder/dependency_manager.rb +11 -4
- data/lib/license_finder/package.rb +28 -18
- data/lib/license_finder/reports/reporter.rb +1 -1
- data/lib/license_finder/tables/dependency.rb +8 -1
- data/lib/templates/html_report.erb +2 -2
- data/license_finder.gemspec +2 -2
- data/readme.md +17 -13
- data/spec/lib/license_finder/cli_spec.rb +46 -4
- data/spec/lib/license_finder/configuration_spec.rb +52 -0
- data/spec/lib/license_finder/dependency_manager_spec.rb +25 -9
- data/spec/lib/license_finder/package_managers/bower_package_spec.rb +2 -2
- data/spec/lib/license_finder/package_managers/bundler_package_spec.rb +13 -9
- data/spec/lib/license_finder/package_managers/gradle_package_spec.rb +1 -1
- data/spec/lib/license_finder/package_managers/maven_package_spec.rb +1 -1
- data/spec/lib/license_finder/package_managers/npm_package_spec.rb +2 -2
- data/spec/lib/license_finder/package_managers/pip_package_spec.rb +1 -1
- data/spec/lib/license_finder/reports/html_report_spec.rb +6 -5
- data/spec/lib/license_finder/reports/reporter_spec.rb +1 -1
- data/spec/lib/license_finder/tables/dependency_spec.rb +14 -1
- data/spec/support/stdout_helpers.rb +25 -0
- metadata +82 -47
- checksums.yaml +0 -7
- data/spec/support/silence_stdout.rb +0 -13
data/readme.md
CHANGED
@@ -152,16 +152,24 @@ whitelist:
|
|
152
152
|
ignore_groups:
|
153
153
|
#- test
|
154
154
|
#- development
|
155
|
+
ignore_dependencies:
|
156
|
+
#- bundler
|
155
157
|
dependencies_file_dir: './doc/'
|
156
158
|
project_name: My Project Name
|
157
159
|
```
|
158
160
|
|
159
|
-
By modifying this file, you can configure license_finder's behavior.
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
161
|
+
By modifying this file, you can configure license_finder's behavior.
|
162
|
+
|
163
|
+
- Licenses in the `whitelist` will be automatically approved.
|
164
|
+
- You can exclude test or development dependencies by setting `ignore_groups`. (Currently this only
|
165
|
+
works for Bundler.)
|
166
|
+
- You can exclude specific dependencies by setting `ignore_dependencies`.
|
167
|
+
(Think carefully before adding dependencies to this list. A likely item to exclude is
|
168
|
+
bundler itself, to avoid noisy changes to the doc files when different people run
|
169
|
+
license_finder with different versions of bundler.)
|
170
|
+
- You can store the license database and text files in another directory by changing
|
171
|
+
`dependencies_file_dir`. And the `project_name`, which defaults to your working
|
172
|
+
directory, appears in the [HTML report](#html-report).
|
165
173
|
|
166
174
|
You can also configure license_finder through the command line. See
|
167
175
|
`license_finder whitelist help`, `license_finder ignored_bundler_groups help`
|
@@ -169,13 +177,9 @@ and `license_finder project_name help` for more details.
|
|
169
177
|
|
170
178
|
## HTML Report
|
171
179
|
|
172
|
-
The HTML report generated by license_finder
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
The individual dependency summary follows a pattern like this:
|
177
|
-
|
178
|
-

|
180
|
+
The HTML report generated by license_finder shows a summary of the project's dependencies
|
181
|
+
and dependencies which need to be approved. The project name at the top of the report can
|
182
|
+
be set in `config/license_finder.yml`.
|
179
183
|
|
180
184
|
## Upgrade for pre 0.8.0 users
|
181
185
|
|
@@ -124,11 +124,9 @@ module LicenseFinder
|
|
124
124
|
|
125
125
|
describe "list" do
|
126
126
|
it "shows the ignored groups in the standard output" do
|
127
|
-
config.should_receive(:ignore_groups).and_return([])
|
127
|
+
config.should_receive(:ignore_groups).and_return(['development'])
|
128
128
|
|
129
|
-
|
130
|
-
subject.list
|
131
|
-
end
|
129
|
+
expect(capture_stdout { subject.list }).to match /development/
|
132
130
|
end
|
133
131
|
end
|
134
132
|
|
@@ -157,6 +155,50 @@ module LicenseFinder
|
|
157
155
|
end
|
158
156
|
end
|
159
157
|
|
158
|
+
describe IgnoredDependencies do
|
159
|
+
let(:config) { LicenseFinder.config }
|
160
|
+
|
161
|
+
describe "list" do
|
162
|
+
context "when there is at least one ignored dependency" do
|
163
|
+
it "shows the ignored dependencies" do
|
164
|
+
expect(config).to receive(:ignore_dependencies).and_return(['bundler'])
|
165
|
+
expect(capture_stdout { subject.list }).to match /bundler/
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "when there are no ignored dependencies" do
|
170
|
+
it "prints '(none)'" do
|
171
|
+
expect(config).to receive(:ignore_dependencies).and_return([])
|
172
|
+
expect(capture_stdout { subject.list }).to match /\(none\)/
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "add" do
|
178
|
+
it "adds the specified group to the ignored groups list" do
|
179
|
+
config.ignore_dependencies.should_receive(:push).with("test")
|
180
|
+
config.should_receive(:save)
|
181
|
+
Reporter.should_receive(:write_reports)
|
182
|
+
|
183
|
+
silence_stdout do
|
184
|
+
subject.add("test")
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "remove" do
|
190
|
+
it "removes the specified group from the ignored groups list" do
|
191
|
+
config.ignore_dependencies.should_receive(:delete).with("test")
|
192
|
+
config.should_receive(:save)
|
193
|
+
Reporter.should_receive(:write_reports)
|
194
|
+
|
195
|
+
silence_stdout do
|
196
|
+
subject.remove("test")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
160
202
|
describe Main do
|
161
203
|
describe "default" do
|
162
204
|
it "checks for action items" do
|
@@ -11,11 +11,23 @@ module LicenseFinder
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
describe "#last_modified" do
|
15
|
+
let(:time) { double :time }
|
16
|
+
before do
|
17
|
+
allow(Configuration::Persistence).to receive(:last_modified) { time }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns the last modified date of the config file' do
|
21
|
+
expect(LicenseFinder::Configuration.new({}).last_modified).to eq time
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
14
25
|
describe '.new' do
|
15
26
|
it "should default missing attributes" do
|
16
27
|
subject = described_class.new({})
|
17
28
|
subject.whitelist.should == []
|
18
29
|
subject.ignore_groups.should == []
|
30
|
+
subject.ignore_dependencies.should == []
|
19
31
|
subject.artifacts.dir.should == Pathname('./doc/')
|
20
32
|
end
|
21
33
|
|
@@ -23,12 +35,14 @@ module LicenseFinder
|
|
23
35
|
attributes = {
|
24
36
|
"whitelist" => nil,
|
25
37
|
"ignore_groups" => nil,
|
38
|
+
"ignore_dependencies" => nil,
|
26
39
|
"dependencies_file_dir" => nil,
|
27
40
|
"project_name" => nil
|
28
41
|
}
|
29
42
|
subject = described_class.new(attributes)
|
30
43
|
subject.whitelist.should == []
|
31
44
|
subject.ignore_groups.should == []
|
45
|
+
subject.ignore_dependencies.should == []
|
32
46
|
subject.artifacts.dir.should == Pathname('./doc/')
|
33
47
|
subject.project_name.should_not be_nil
|
34
48
|
end
|
@@ -37,12 +51,14 @@ module LicenseFinder
|
|
37
51
|
attributes = {
|
38
52
|
"whitelist" => %w{a whitelist},
|
39
53
|
"ignore_groups" => %w{test development},
|
54
|
+
"ignore_dependencies" => %w{bundler},
|
40
55
|
"dependencies_file_dir" => "some/path",
|
41
56
|
"project_name" => "my_app"
|
42
57
|
}
|
43
58
|
subject = described_class.new(attributes)
|
44
59
|
subject.whitelist.should == %w{a whitelist}
|
45
60
|
subject.ignore_groups.should == %w{test development}
|
61
|
+
subject.ignore_dependencies.should == %w{bundler}
|
46
62
|
subject.artifacts.dir.should == Pathname("some/path")
|
47
63
|
subject.project_name.should == "my_app"
|
48
64
|
end
|
@@ -77,6 +93,7 @@ module LicenseFinder
|
|
77
93
|
{
|
78
94
|
'whitelist' => ['my_gem'],
|
79
95
|
'ignore_groups' => ['other_group', 'test'],
|
96
|
+
'ignore_dependencies' => ['bundler'],
|
80
97
|
'project_name' => "New Project Name",
|
81
98
|
'dependencies_file_dir' => "./deps"
|
82
99
|
}
|
@@ -91,6 +108,7 @@ module LicenseFinder
|
|
91
108
|
config = described_class.new(attributes)
|
92
109
|
config.whitelist << 'my_gem'
|
93
110
|
config.ignore_groups << 'test'
|
111
|
+
config.ignore_dependencies << 'bundler'
|
94
112
|
|
95
113
|
Configuration::Persistence.should_receive(:set).with(attributes)
|
96
114
|
config.save
|
@@ -98,6 +116,28 @@ module LicenseFinder
|
|
98
116
|
end
|
99
117
|
end
|
100
118
|
|
119
|
+
describe Configuration::Artifacts do
|
120
|
+
describe "#last_refreshed" do
|
121
|
+
let(:database_modified_time) { 1 }
|
122
|
+
let(:text_modified_time) { 2 }
|
123
|
+
let(:detailed_text_modified_time) { 3 }
|
124
|
+
let(:html_modified_time) { 4 }
|
125
|
+
let(:markdown_modified_time) { 5 }
|
126
|
+
|
127
|
+
before do
|
128
|
+
allow(File).to receive(:mtime).with(Pathname('./doc/dependencies.db')) { database_modified_time }
|
129
|
+
allow(File).to receive(:mtime).with(Pathname('./doc/dependencies.csv')) { text_modified_time }
|
130
|
+
allow(File).to receive(:mtime).with(Pathname('./doc/dependencies_detailed.csv')) { detailed_text_modified_time }
|
131
|
+
allow(File).to receive(:mtime).with(Pathname('./doc/dependencies.html')) { html_modified_time }
|
132
|
+
allow(File).to receive(:mtime).with(Pathname('./doc/dependencies.md')) { markdown_modified_time }
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'returns the earliest modified date of the config file' do
|
136
|
+
expect(described_class.new(Pathname('./doc')).last_refreshed).to eq database_modified_time
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
101
141
|
describe Configuration::Persistence do
|
102
142
|
describe ".get" do
|
103
143
|
it "should use saved configuration" do
|
@@ -150,5 +190,17 @@ module LicenseFinder
|
|
150
190
|
described_class.init
|
151
191
|
end
|
152
192
|
end
|
193
|
+
|
194
|
+
describe ".last_modified" do
|
195
|
+
let(:time) { double :time }
|
196
|
+
let(:config_path) { Pathname.new('.').join('config').join('license_finder.yml') }
|
197
|
+
before do
|
198
|
+
allow(File).to receive(:mtime).with(config_path) { time }
|
199
|
+
end
|
200
|
+
|
201
|
+
it "returns the last time the yml file was modified" do
|
202
|
+
expect(described_class.last_modified).to eq time
|
203
|
+
end
|
204
|
+
end
|
153
205
|
end
|
154
206
|
end
|
@@ -148,27 +148,43 @@ module LicenseFinder
|
|
148
148
|
context "when the database has not changed" do
|
149
149
|
before do
|
150
150
|
Digest::SHA2.stub_chain(:file, :hexdigest) { 5 }
|
151
|
+
allow(config).to receive(:last_modified) { config_last_update }
|
152
|
+
allow(config.artifacts).to receive(:last_refreshed) { artifacts_last_update }
|
151
153
|
end
|
152
154
|
|
153
|
-
context "
|
155
|
+
context "and the reports do not exist" do
|
154
156
|
before do
|
155
|
-
config.artifacts.stub(:html_file).and_return(
|
157
|
+
config.artifacts.stub(:html_file).and_return(file_does_not_exist)
|
156
158
|
end
|
157
159
|
|
158
|
-
it "
|
159
|
-
Reporter.
|
160
|
+
it "writes reports" do
|
161
|
+
Reporter.should_receive(:write_reports)
|
160
162
|
DependencyManager.modifying {}
|
161
163
|
end
|
162
164
|
end
|
163
165
|
|
164
|
-
context "
|
166
|
+
context "and the reports exist" do
|
165
167
|
before do
|
166
|
-
config.artifacts.stub(:html_file).and_return(
|
168
|
+
config.artifacts.stub(:html_file).and_return(file_exists)
|
167
169
|
end
|
168
170
|
|
169
|
-
|
170
|
-
|
171
|
-
|
171
|
+
context "and configs are newer than the reports" do
|
172
|
+
let(:config_last_update) { 4 }
|
173
|
+
let(:artifacts_last_update) { 1 }
|
174
|
+
it "writes reports" do
|
175
|
+
expect(Reporter).to receive(:write_reports)
|
176
|
+
DependencyManager.modifying {}
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "and configs are older than the reports" do
|
181
|
+
let(:config_last_update) { 4 }
|
182
|
+
let(:artifacts_last_update) { 6 }
|
183
|
+
|
184
|
+
it "does not write reports" do
|
185
|
+
expect(Reporter).not_to receive(:write_reports)
|
186
|
+
DependencyManager.modifying {}
|
187
|
+
end
|
172
188
|
end
|
173
189
|
end
|
174
190
|
end
|
@@ -56,7 +56,7 @@ module LicenseFinder
|
|
56
56
|
|
57
57
|
it "returns 'multiple licenses' if there's more than one license" do
|
58
58
|
package = BowerPackage.new({ "pkgMeta" => {"licenses" => ["MIT", "BSD"]}, "canonicalDir" => "/some/path" })
|
59
|
-
expect(package.license.name).to eq("multiple licenses")
|
59
|
+
expect(package.license.name).to eq("multiple licenses: MIT, BSD")
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -82,7 +82,7 @@ module LicenseFinder
|
|
82
82
|
double(:second_file, license: License.find_by_name('Second Detected License'))
|
83
83
|
])
|
84
84
|
|
85
|
-
subject.license.name.should == "
|
85
|
+
subject.license.name.should == "multiple licenses: First Detected License, Second Detected License"
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
@@ -36,21 +36,25 @@ module LicenseFinder
|
|
36
36
|
stub_license_files [double(:file, license: License.find_by_name('Detected License'))]
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
gemspec.licenses = ['MIT', 'Expat']
|
39
|
+
context 'if the gemspec provides two synonymous licenses' do
|
40
|
+
before { gemspec.licenses = ['MIT', 'Expat'] }
|
41
41
|
|
42
|
-
|
42
|
+
it 'returns the license only once' do
|
43
|
+
subject.license.name.should == "MIT"
|
44
|
+
end
|
43
45
|
end
|
44
46
|
|
45
|
-
|
46
|
-
gemspec.licenses = ['First Gemspec License', 'Second Gemspec License']
|
47
|
+
context 'if the gemspec provides many licenses' do
|
48
|
+
before { gemspec.licenses = ['First Gemspec License', 'Second Gemspec License'] }
|
47
49
|
|
48
|
-
|
50
|
+
it "returns 'multiple licenses' with the names of the licenses from the gemspec (but not those from detected files)" do
|
51
|
+
subject.license.name.should == "multiple licenses: First Gemspec License, Second Gemspec License"
|
52
|
+
end
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
52
56
|
context "when there is nothing in the spec" do
|
53
|
-
it "returns a license in a file if only one unique license detected" do
|
57
|
+
it "returns a license in a file if there is only one unique license detected" do
|
54
58
|
stub_license_files([
|
55
59
|
double(:first_file, license: License.find_by_name('MIT')),
|
56
60
|
double(:second_file, license: License.find_by_name('Expat'))
|
@@ -65,13 +69,13 @@ module LicenseFinder
|
|
65
69
|
subject.license.name.should == "other"
|
66
70
|
end
|
67
71
|
|
68
|
-
it "returns '
|
72
|
+
it "returns 'multiple licenses' if there are many licenses in files" do
|
69
73
|
stub_license_files([
|
70
74
|
double(:first_file, license: License.find_by_name('First Detected License')),
|
71
75
|
double(:second_file, license: License.find_by_name('Second Detected License'))
|
72
76
|
])
|
73
77
|
|
74
|
-
subject.license.name.should == "
|
78
|
+
subject.license.name.should == "multiple licenses: First Detected License, Second Detected License"
|
75
79
|
end
|
76
80
|
end
|
77
81
|
end
|
@@ -40,7 +40,7 @@ module LicenseFinder
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it "returns 'multiple licenses'" do
|
43
|
-
subject.license.name.should == 'multiple licenses'
|
43
|
+
subject.license.name.should == 'multiple licenses: Eclipse Public License - v 1.0, GNU Lesser General Public License'
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -52,7 +52,7 @@ module LicenseFinder
|
|
52
52
|
|
53
53
|
it "returns 'multiple licenses' if there's more than one license" do
|
54
54
|
package = NpmPackage.new({ "licenses" => ["MIT", "BSD"], "path" => "/some/path" })
|
55
|
-
expect(package.license.name).to eq("multiple licenses")
|
55
|
+
expect(package.license.name).to eq("multiple licenses: MIT, BSD")
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -78,7 +78,7 @@ module LicenseFinder
|
|
78
78
|
double(:second_file, license: License.find_by_name('Second Detected License'))
|
79
79
|
])
|
80
80
|
|
81
|
-
subject.license.name.should == "
|
81
|
+
subject.license.name.should == "multiple licenses: First Detected License, Second Detected License"
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -4,8 +4,9 @@ require "capybara"
|
|
4
4
|
module LicenseFinder
|
5
5
|
describe HtmlReport do
|
6
6
|
describe "#to_s" do
|
7
|
+
let(:dependency_name) { "the-name" }
|
7
8
|
let(:dependency) do
|
8
|
-
dep = Dependency.create name:
|
9
|
+
dep = Dependency.create name: dependency_name
|
9
10
|
dep.apply_better_license License.find_by_name("MIT")
|
10
11
|
dep
|
11
12
|
end
|
@@ -64,9 +65,9 @@ module LicenseFinder
|
|
64
65
|
|
65
66
|
it "should show the relationships" do
|
66
67
|
should have_text "(foo group)"
|
67
|
-
should have_text "
|
68
|
+
should have_text "#{dependency_name} is required by:"
|
68
69
|
should have_text "foo parent"
|
69
|
-
should have_text "
|
70
|
+
should have_text "#{dependency_name} relies on:"
|
70
71
|
should have_text "foo child"
|
71
72
|
end
|
72
73
|
end
|
@@ -74,8 +75,8 @@ module LicenseFinder
|
|
74
75
|
context "when the gem has no relationships" do
|
75
76
|
it "should not show any relationships" do
|
76
77
|
should_not have_text "()"
|
77
|
-
should_not have_text "
|
78
|
-
should_not have_text "
|
78
|
+
should_not have_text "#{dependency_name} is required by:"
|
79
|
+
should_not have_text "#{dependency_name} relies on:"
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
@@ -6,7 +6,7 @@ module LicenseFinder
|
|
6
6
|
subject { Reporter.write_reports }
|
7
7
|
|
8
8
|
before do
|
9
|
-
Dependency.stub(:
|
9
|
+
Dependency.stub(:acknowledged) { [double(:dep)] }
|
10
10
|
|
11
11
|
MarkdownReport.stub(:of) { 'markdown report' }
|
12
12
|
DetailedTextReport.stub(:of) { 'detailed csv report' }
|
@@ -5,11 +5,14 @@ module LicenseFinder
|
|
5
5
|
describe '.unapproved' do
|
6
6
|
before do
|
7
7
|
License.find_by_name('MIT').stub(:whitelisted? => true)
|
8
|
+
allow(LicenseFinder.config).to receive(:ignore_dependencies) { ['this ignored dependency', 'that ignored dependency'] }
|
8
9
|
end
|
9
10
|
|
10
|
-
it "should return all unapproved dependencies" do
|
11
|
+
it "should return all unapproved dependencies that are not ignored" do
|
11
12
|
dependency = Dependency.create(name: "unapproved dependency", version: '0.0.1')
|
12
13
|
approved = Dependency.create(name: "approved dependency", version: '0.0.1')
|
14
|
+
this_ignored = Dependency.create(name: "this ignored dependency", version: '0.0.1')
|
15
|
+
that_ignored = Dependency.create(name: "that ignored dependency", version: '0.0.1')
|
13
16
|
approved.approve!
|
14
17
|
whitelisted = Dependency.create(name: "approved dependency", version: '0.0.1')
|
15
18
|
whitelisted.license = License.find_by_name('MIT')
|
@@ -37,6 +40,16 @@ module LicenseFinder
|
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
43
|
+
describe ".acknowledged" do
|
44
|
+
it "returns all dependencies that are not ignored" do
|
45
|
+
acknowledged_dependency = Dependency.create(name: "acknowledged dependency", version: '0.0.1')
|
46
|
+
ignored_dependency = Dependency.create(name: "ignored dependency", version: '0.0.1')
|
47
|
+
allow(LicenseFinder.config).to receive(:ignore_dependencies) { [ignored_dependency.name] }
|
48
|
+
|
49
|
+
expect(Dependency.acknowledged).to match_array [acknowledged_dependency]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
40
53
|
describe '#approve!' do
|
41
54
|
it "should update the database to show the dependency is approved" do
|
42
55
|
dependency = Dependency.named("foo")
|