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/CHANGELOG.rdoc
CHANGED
@@ -1,4 +1,24 @@
|
|
1
|
-
=== 1.0.
|
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
|
+
|
data/files/license_finder.yml
CHANGED
data/lib/license_finder/cli.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
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
|
28
|
-
licenses_from_spec
|
29
|
-
elsif
|
30
|
-
licenses_from_files
|
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
|
39
|
-
(
|
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
|
43
|
-
licenses_from_spec.uniq.size
|
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
|
47
|
-
|
48
|
-
end
|
48
|
+
# def one_license_from_spec?
|
49
|
+
# licenses_from_spec.uniq.size == 1
|
50
|
+
# end
|
49
51
|
|
50
|
-
def
|
51
|
-
|
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
|
-
|
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
|
@@ -26,7 +26,14 @@ module LicenseFinder
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.unapproved
|
29
|
-
|
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
|
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
|
108
|
+
<dt><%=dependency.name%> relies on:</dt>
|
109
109
|
<dd><%= dependency.children.map(&:name).join(", ") -%></dd>
|
110
110
|
</dl>
|
111
111
|
<% end -%>
|
data/license_finder.gemspec
CHANGED
@@ -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.
|
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."
|