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
@@ -1,4 +1,24 @@
1
- === 1.0.0 / Unreleased
1
+ === 1.0.1 / 2014-05-28
2
+
3
+ * Features
4
+
5
+ * For dependencies with multiple licenses, the dependency is listed as
6
+ 'multiple licenses' along with the names of each license
7
+ * Added 'ignore_dependencies' config option to allow specific
8
+ dependencies to be excluded from reports.
9
+
10
+ * Bugfixes
11
+
12
+ * Dependency reports generate when license_finder.yml updates
13
+ * Dependency reports generate when config is changed through the command line
14
+
15
+ === 1.0.0.1 / 2014-05-23
16
+
17
+ * Bugfixes
18
+
19
+ * LicenseFinder detects its own license
20
+
21
+ === 1.0.0 / 2014-04-03
2
22
 
3
23
  * Features
4
24
 
@@ -0,0 +1,16 @@
1
+ Feature: Ignore Dependencies
2
+ As a developer
3
+ I want to ignore certain dependencies
4
+ To avoid noisy doc changes when there are safe dependencies with high version churn
5
+
6
+ Scenario: Select dependencies can be ignored
7
+ Given I have an app that depends on bundler
8
+ And I ignore the bundler dependency
9
+ When I get the ignored dependencies
10
+ Then I should see 'bundler' in the output
11
+ And I should not see 'bundler' in the dependency docs
12
+
13
+ Scenario: Ignored dependencies do not appear in the unapproved list
14
+ Given I have an app that depends on bundler
15
+ When I ignore the bundler dependency
16
+ Then the bundler dependency is not listed as an action item
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  Then(/^it creates a config directory with the license_finder config$/) do
24
24
  @user.config_path.should be_exist
25
- text = "---\nwhitelist:\n#- MIT\n#- Apache 2.0\nignore_groups:\n#- test\n#- development\ndependencies_file_dir: './doc/'\nproject_name: # project name\n"
25
+ text = "---\nwhitelist:\n#- MIT\n#- Apache 2.0\nignore_groups:\n#- test\n#- development\nignore_dependencies:\n#- bundler\ndependencies_file_dir: './doc/'\nproject_name: # project name\n"
26
26
  @user.config_file.read.should == text.gsub(/^\s+/, "")
27
27
  end
28
28
 
@@ -0,0 +1,35 @@
1
+ Given(/^I have an app that depends on bundler$/) do
2
+ @user = ::DSL::User.new
3
+ @user.create_ruby_app
4
+ @user.create_gem 'bundler_faker', license: 'Whatever'
5
+ @user.depend_on_local_gem 'bundler_faker', groups: ['test', 'development', 'production']
6
+ @user.create_gem 'gpl_gem', license: 'GPL'
7
+ @user.depend_on_local_gem 'gpl_gem', groups: ['test']
8
+ end
9
+
10
+ Given(/^I ignore the bundler dependency$/) do
11
+ @user.execute_command('license_finder ignored_dependencies add bundler_faker')
12
+ end
13
+
14
+ When(/^I get the ignored dependencies$/) do
15
+ @user.execute_command('license_finder ignored_dependencies list')
16
+ end
17
+
18
+ Then(/^I should see 'bundler' in the output$/) do
19
+ expect(@user).to be_seeing 'bundler_faker'
20
+ end
21
+
22
+ Then(/^the bundler dependency is not listed as an action item$/) do
23
+ @user.execute_command('license_finder > /dev/null')
24
+ @user.execute_command('license_finder action_items')
25
+ expect(@user).not_to be_seeing 'bundler_faker'
26
+ end
27
+
28
+ Then(/^I should not see 'bundler' in the dependency docs$/)do
29
+ @user.execute_command('license_finder')
30
+ dependencies_csv_path = @user.app_path.join('doc', 'dependencies.csv')
31
+ dependencies_csv = File.open(dependencies_csv_path, 'r')
32
+
33
+ expect(dependencies_csv.read).not_to match /bundler_faker/
34
+ end
35
+
@@ -5,5 +5,7 @@ whitelist:
5
5
  ignore_groups:
6
6
  #- test
7
7
  #- development
8
+ ignore_dependencies:
9
+ #- bundler
8
10
  dependencies_file_dir: './doc/'
9
11
  project_name: # project name
@@ -11,12 +11,43 @@ module LicenseFinder
11
11
 
12
12
  private
13
13
 
14
+ def sync_with_spinner
15
+ die_on_error {
16
+ spinner {
17
+ DependencyManager.sync_with_package_managers
18
+ }
19
+ }
20
+ end
21
+
14
22
  def die_on_error
15
23
  yield
16
24
  rescue LicenseFinder::Error => e
17
25
  say e.message, :red
18
26
  exit 1
19
27
  end
28
+
29
+ def spinner
30
+ if options[:quiet]
31
+ yield
32
+ else
33
+ begin
34
+ thread = Thread.new {
35
+ wheel = '\|/-'
36
+ i = 0
37
+ while true do
38
+ print "\r ---------- #{wheel[i]} ----------"
39
+ i = (i + 1) % 4
40
+ end
41
+ }
42
+ yield
43
+ ensure
44
+ if thread
45
+ thread.kill
46
+ puts "\r" + " "*24
47
+ end
48
+ end
49
+ end
50
+ end
20
51
  end
21
52
 
22
53
  # Thor fix for `license_finder <subcommand> help <action>`
@@ -73,7 +104,7 @@ module LicenseFinder
73
104
  yield
74
105
 
75
106
  LicenseFinder.config.save
76
- Reporter.write_reports
107
+ sync_with_spinner
77
108
  }
78
109
  end
79
110
  end
@@ -150,18 +181,52 @@ module LicenseFinder
150
181
  end
151
182
  end
152
183
 
184
+ class IgnoredDependencies < ConfigSubcommand
185
+ desc "list", "List all the ignored dependencies"
186
+ def list
187
+ ignored = LicenseFinder.config.ignore_dependencies
188
+
189
+ say "Ignored Dependencies:", :blue
190
+ if ignored.any?
191
+ ignored.each do |group|
192
+ say group
193
+ end
194
+ else
195
+ say '(none)'
196
+ end
197
+ end
198
+
199
+ desc "add DEPENDENCY", "Add a dependency to be ignored"
200
+ def add(group)
201
+ modifying {
202
+ LicenseFinder.config.ignore_dependencies.push(group)
203
+ }
204
+ say "Added #{group} to the ignored dependencies"
205
+ end
206
+
207
+ desc "remove DEPENDENCY", "Remove a dependency from the ignored dependencies"
208
+ def remove(group)
209
+ modifying {
210
+ LicenseFinder.config.ignore_dependencies.delete(group)
211
+ }
212
+ say "Removed #{group} from the ignored dependencies"
213
+ end
214
+ end
215
+
153
216
  class Main < Base
154
217
  method_option :quiet, type: :boolean, desc: "silences loading output"
155
218
  desc "rescan", "Find new dependencies. (Default action)"
156
219
  def rescan
157
- die_on_error {
158
- spinner {
159
- DependencyManager.sync_with_package_managers
160
- }
161
- }
220
+ sync_with_spinner
221
+ show_results
222
+ end
162
223
 
224
+ desc "show_results", "Display ignored dependencies and action items"
225
+ def show_results
226
+ IgnoredDependencies.new.list
163
227
  action_items
164
228
  end
229
+
165
230
  default_task :rescan
166
231
 
167
232
  method_option :approver, desc: "The person granting the approval"
@@ -206,33 +271,10 @@ module LicenseFinder
206
271
 
207
272
  subcommand "dependencies", Dependencies, "Manually manage dependencies that your package managers are not aware of"
208
273
  subcommand "ignored_bundler_groups", IgnoredBundlerGroups, "Manage ignored Bundler groups"
274
+ subcommand "ignored_dependencies", IgnoredDependencies, "Manage ignored dependencies"
209
275
  subcommand "whitelist", Whitelist, "Manage whitelisted licenses"
210
276
  subcommand "project_name", ProjectName, "Manage the project name"
211
277
 
212
- private
213
-
214
- def spinner
215
- if options[:quiet]
216
- yield
217
- else
218
- begin
219
- thread = Thread.new {
220
- wheel = '\|/-'
221
- i = 0
222
- while true do
223
- print "\r ---------- #{wheel[i]} ----------"
224
- i = (i + 1) % 4
225
- end
226
- }
227
- yield
228
- ensure
229
- if thread
230
- thread.kill
231
- puts "\r" + " "*24
232
- end
233
- end
234
- end
235
- end
236
278
  end
237
279
  end
238
280
  end
@@ -7,6 +7,10 @@ module LicenseFinder
7
7
  prepare(Persistence.get)
8
8
  end
9
9
 
10
+ def last_modified
11
+ Persistence.last_modified
12
+ end
13
+
10
14
  def self.move!
11
15
  config = prepare(Persistence.get.merge('dependencies_file_dir' => './doc/'))
12
16
  config.save
@@ -24,11 +28,12 @@ module LicenseFinder
24
28
  result
25
29
  end
26
30
 
27
- attr_accessor :whitelist, :ignore_groups, :artifacts, :project_name
31
+ attr_accessor :whitelist, :ignore_groups, :ignore_dependencies, :artifacts, :project_name
28
32
 
29
33
  def initialize(config)
30
34
  @whitelist = Array(config['whitelist'])
31
35
  @ignore_groups = Array(config["ignore_groups"])
36
+ @ignore_dependencies = Array(config["ignore_dependencies"])
32
37
  @artifacts = Artifacts.new(Pathname(config['dependencies_file_dir'] || './doc/'))
33
38
  @project_name = config['project_name'] || determine_project_name
34
39
  end
@@ -43,6 +48,7 @@ module LicenseFinder
43
48
  {
44
49
  'whitelist' => whitelist.uniq,
45
50
  'ignore_groups' => ignore_groups.uniq,
51
+ 'ignore_dependencies' => ignore_dependencies.uniq,
46
52
  'dependencies_file_dir' => artifacts.dir.to_s,
47
53
  'project_name' => project_name
48
54
  }
@@ -92,6 +98,12 @@ module LicenseFinder
92
98
  def legacy_text_file
93
99
  join("dependencies.txt")
94
100
  end
101
+
102
+ def last_refreshed
103
+ [database_file, text_file, detailed_text_file, html_file, markdown_file].map do |path|
104
+ File.mtime(path)
105
+ end.min
106
+ end
95
107
  end
96
108
 
97
109
  module Persistence
@@ -111,6 +123,10 @@ module LicenseFinder
111
123
  file.open('w') { |f| f.write(YAML.dump(hash)) }
112
124
  end
113
125
 
126
+ def last_modified
127
+ File.mtime(file)
128
+ end
129
+
114
130
  private
115
131
 
116
132
  def inited?
@@ -38,10 +38,9 @@ module LicenseFinder
38
38
  result = DB.transaction { yield }
39
39
  checksum_after = checksum
40
40
 
41
- unless checksum_before == checksum_after
42
- Reporter.write_reports
43
- end
44
- unless LicenseFinder.config.artifacts.html_file.exist?
41
+ database_changed = checksum_before != checksum_after
42
+
43
+ if database_changed || reports_do_not_exist || reports_are_stale
45
44
  Reporter.write_reports
46
45
  end
47
46
 
@@ -50,6 +49,14 @@ module LicenseFinder
50
49
 
51
50
  private # not really private, but it looks like it is!
52
51
 
52
+ def self.reports_do_not_exist
53
+ !(LicenseFinder.config.artifacts.html_file.exist?)
54
+ end
55
+
56
+ def self.reports_are_stale
57
+ LicenseFinder.config.last_modified > LicenseFinder.config.artifacts.last_refreshed
58
+ end
59
+
53
60
  def self.current_packages
54
61
  package_managers.select(&:active?).map(&:current_packages).flatten
55
62
  end
@@ -24,32 +24,38 @@ module LicenseFinder
24
24
  private
25
25
 
26
26
  def determine_license
27
- if one_license_from_spec?
28
- licenses_from_spec.first
29
- elsif no_licenses_from_spec? && one_license_from_files?
30
- licenses_from_files.first
31
- elsif multiple_licenses_from_spec_and_files?
32
- multiple_licenses
27
+ if licenses_from_spec.any?
28
+ choose_license_from licenses_from_spec
29
+ elsif licenses_from_files.any?
30
+ choose_license_from licenses_from_files
33
31
  else
34
32
  default_license
35
33
  end
36
34
  end
37
35
 
38
- def multiple_licenses_from_spec_and_files?
39
- (licenses_from_spec+licenses_from_spec).uniq.size > 1
36
+ def choose_license_from licenses
37
+ if ( licenses.uniq.size > 1 )
38
+ License.find_by_name "multiple licenses: #{(licenses).map(&:name).uniq.join(', ')}"
39
+ else
40
+ licenses.first
41
+ end
40
42
  end
41
43
 
42
- def one_license_from_spec?
43
- licenses_from_spec.uniq.size == 1
44
- end
44
+ # def multiple_licenses_from_spec_and_files?
45
+ # (licenses_from_spec+licenses_from_files).uniq.size > 1
46
+ # end
45
47
 
46
- def one_license_from_files?
47
- licenses_from_files.uniq.size == 1
48
- end
48
+ # def one_license_from_spec?
49
+ # licenses_from_spec.uniq.size == 1
50
+ # end
49
51
 
50
- def no_licenses_from_spec?
51
- licenses_from_spec.uniq.size == 0
52
- end
52
+ # def one_license_from_files?
53
+ # licenses_from_files.uniq.size == 1
54
+ # end
55
+
56
+ # def no_licenses_from_spec?
57
+ # licenses_from_spec.uniq.size == 0
58
+ # end
53
59
 
54
60
  def licenses_from_spec
55
61
  license_names_from_spec.map do |name|
@@ -66,7 +72,11 @@ module LicenseFinder
66
72
  end
67
73
 
68
74
  def multiple_licenses
69
- License.find_by_name 'multiple licenses'
75
+ if ( licenses_from_spec.uniq.size > 1 )
76
+ License.find_by_name "multiple licenses: #{(licenses_from_spec).map(&:name).uniq.join(', ')}"
77
+ else
78
+ License.find_by_name "multiple licenses: #{(licenses_from_files).map(&:name).uniq.join(', ')}"
79
+ end
70
80
  end
71
81
 
72
82
  def default_license
@@ -3,7 +3,7 @@ module LicenseFinder
3
3
  extend self
4
4
 
5
5
  def write_reports
6
- dependencies = Dependency.all
6
+ dependencies = Dependency.acknowledged
7
7
  artifacts = LicenseFinder.config.artifacts
8
8
 
9
9
  write_file artifacts.text_file, TextReport.of(dependencies)
@@ -26,7 +26,14 @@ module LicenseFinder
26
26
  end
27
27
 
28
28
  def self.unapproved
29
- all.reject(&:approved?)
29
+ acknowledged.reject(&:approved?)
30
+ end
31
+
32
+ def self.acknowledged
33
+ ignored_dependencies = LicenseFinder.config.ignore_dependencies
34
+ all.reject do |dependency|
35
+ ignored_dependencies.include? dependency.name
36
+ end
30
37
  end
31
38
 
32
39
  def self.named(name)
@@ -99,13 +99,13 @@
99
99
  <p><%= dependency.description %></p>
100
100
  <% if dependency.parents.any? -%>
101
101
  <dl>
102
- <dt>Parents</dt>
102
+ <dt><%=dependency.name%> is required by:</dt>
103
103
  <dd><%= dependency.parents.map(&:name).join(", ") -%></dd>
104
104
  </dl>
105
105
  <% end -%>
106
106
  <% if dependency.children.any? -%>
107
107
  <dl>
108
- <dt>Children</dt>
108
+ <dt><%=dependency.name%> relies on:</dt>
109
109
  <dd><%= dependency.children.map(&:name).join(", ") -%></dd>
110
110
  </dl>
111
111
  <% end -%>
@@ -3,8 +3,8 @@ require './lib/license_finder/platform'
3
3
  Gem::Specification.new do |s|
4
4
  s.required_ruby_version = '>= 1.9.3'
5
5
  s.name = "license_finder"
6
- s.version = "1.0.0.1"
7
- s.authors = ["Jacob Maine", "Matthew Kane Parker", "Ian Lesperance", "David Edwards", "Paul Meskers", "Brent Wheeldon", "Trevor John", "David Tengdin", "William Ramsey"]
6
+ s.version = "1.0.1"
7
+ s.authors = ["Jacob Maine", "Matthew Kane Parker", "Ian Lesperance", "David Edwards", "Paul Meskers", "Brent Wheeldon", "Trevor John", "David Tengdin", "William Ramsey", "David Dening"]
8
8
  s.email = ["commoncode@pivotalabs.com"]
9
9
  s.homepage = "https://github.com/pivotal/LicenseFinder"
10
10
  s.summary = "Audit the OSS licenses of your application's dependencies."