license_finder 1.0.0.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/CHANGELOG.rdoc +21 -1
  2. data/features/configure_ignore_dependencies.feature +16 -0
  3. data/features/step_definitions/cli_steps.rb +1 -1
  4. data/features/step_definitions/configure_ignore_dependencies.rb +35 -0
  5. data/files/license_finder.yml +2 -0
  6. data/lib/license_finder/cli.rb +72 -30
  7. data/lib/license_finder/configuration.rb +17 -1
  8. data/lib/license_finder/dependency_manager.rb +11 -4
  9. data/lib/license_finder/package.rb +28 -18
  10. data/lib/license_finder/reports/reporter.rb +1 -1
  11. data/lib/license_finder/tables/dependency.rb +8 -1
  12. data/lib/templates/html_report.erb +2 -2
  13. data/license_finder.gemspec +2 -2
  14. data/readme.md +17 -13
  15. data/spec/lib/license_finder/cli_spec.rb +46 -4
  16. data/spec/lib/license_finder/configuration_spec.rb +52 -0
  17. data/spec/lib/license_finder/dependency_manager_spec.rb +25 -9
  18. data/spec/lib/license_finder/package_managers/bower_package_spec.rb +2 -2
  19. data/spec/lib/license_finder/package_managers/bundler_package_spec.rb +13 -9
  20. data/spec/lib/license_finder/package_managers/gradle_package_spec.rb +1 -1
  21. data/spec/lib/license_finder/package_managers/maven_package_spec.rb +1 -1
  22. data/spec/lib/license_finder/package_managers/npm_package_spec.rb +2 -2
  23. data/spec/lib/license_finder/package_managers/pip_package_spec.rb +1 -1
  24. data/spec/lib/license_finder/reports/html_report_spec.rb +6 -5
  25. data/spec/lib/license_finder/reports/reporter_spec.rb +1 -1
  26. data/spec/lib/license_finder/tables/dependency_spec.rb +14 -1
  27. data/spec/support/stdout_helpers.rb +25 -0
  28. metadata +82 -47
  29. checksums.yaml +0 -7
  30. 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. Licenses
160
- in the `whitelist` will be automatically approved. You can exclude test or
161
- development dependencies by setting `ignore_groups`. (Currently this only
162
- works for Bundler.) You can store the license database and text files in
163
- another directory by changing `dependencies_file_dir`. And the `project_name`,
164
- which defaults to your working directory, appears in the [HTML report](#html-report).
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 has two sections, an overview at the top, and then a series of dependency summaries afterwards.
173
-
174
- ![HTML Report](files/report_breakdown.png)
175
-
176
- The individual dependency summary follows a pattern like this:
177
-
178
- ![HTML Report](files/dependency_breakdown.png)
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
- silence_stdout do
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 "when the reports exist" do
155
+ context "and the reports do not exist" do
154
156
  before do
155
- config.artifacts.stub(:html_file).and_return(file_exists)
157
+ config.artifacts.stub(:html_file).and_return(file_does_not_exist)
156
158
  end
157
159
 
158
- it "does not write reports" do
159
- Reporter.should_not_receive(:write_reports)
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 "when the reports do not exist" do
166
+ context "and the reports exist" do
165
167
  before do
166
- config.artifacts.stub(:html_file).and_return(file_does_not_exist)
168
+ config.artifacts.stub(:html_file).and_return(file_exists)
167
169
  end
168
170
 
169
- it "writes reports" do
170
- Reporter.should_receive(:write_reports)
171
- DependencyManager.modifying {}
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 == "other"
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
- it "returns the license from the gemspec if only one unique license provided" do
40
- gemspec.licenses = ['MIT', 'Expat']
39
+ context 'if the gemspec provides two synonymous licenses' do
40
+ before { gemspec.licenses = ['MIT', 'Expat'] }
41
41
 
42
- subject.license.name.should == "MIT"
42
+ it 'returns the license only once' do
43
+ subject.license.name.should == "MIT"
44
+ end
43
45
  end
44
46
 
45
- it "returns 'other' if the gemspec provides many" do
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
- subject.license.name.should == "multiple licenses"
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 'other' if there are many licenses in files" do
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 == "other"
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
 
@@ -46,7 +46,7 @@ module LicenseFinder
46
46
  end
47
47
 
48
48
  it "returns 'multiple licenses'" do
49
- subject.license.name.should == 'multiple licenses'
49
+ subject.license.name.should == 'multiple licenses: Common Public License Version 1.0, Apache 2'
50
50
  end
51
51
  end
52
52
 
@@ -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 == "other"
81
+ subject.license.name.should == "multiple licenses: First Detected License, Second Detected License"
82
82
  end
83
83
  end
84
84
  end
@@ -73,7 +73,7 @@ module LicenseFinder
73
73
 
74
74
  subject = make_package(data)
75
75
 
76
- expect(subject.license.name).to eq('multiple licenses')
76
+ expect(subject.license.name).to eq('multiple licenses: Apache 2.0 License, GPL')
77
77
  end
78
78
  end
79
79
 
@@ -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: "the-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 "Parents"
68
+ should have_text "#{dependency_name} is required by:"
68
69
  should have_text "foo parent"
69
- should have_text "Children"
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 "Parents"
78
- should_not have_text "Children"
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(:all) { [double(:dep)] }
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")