license_finder 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +22 -0
- data/README.markdown +56 -92
- data/Rakefile +1 -1
- data/bin/license_finder +1 -1
- data/features/approve_dependencies.feature +49 -0
- data/features/html_report.feature +48 -0
- data/features/license_finder.feature +36 -0
- data/features/license_finder_rake_task.feature +36 -0
- data/features/rails_rake.feature +9 -0
- data/features/step_definitions/steps.rb +78 -31
- data/features/text_report.feature +27 -0
- data/lib/{templates/Apache.txt → data/licenses/Apache2.txt} +0 -0
- data/lib/{templates → data/licenses}/BSD.txt +0 -0
- data/lib/{templates → data/licenses}/GPLv2.txt +0 -0
- data/lib/{templates → data/licenses}/ISC.txt +0 -0
- data/lib/{templates → data/licenses}/LGPL.txt +0 -0
- data/lib/{templates → data/licenses}/MIT.txt +0 -0
- data/lib/{templates → data/licenses}/NewBSD.txt +0 -0
- data/lib/{templates → data/licenses}/Ruby.txt +0 -0
- data/lib/{templates → data/licenses}/SimplifiedBSD.txt +0 -0
- data/lib/license_finder.rb +11 -32
- data/lib/license_finder/bundle.rb +33 -0
- data/lib/license_finder/bundled_gem.rb +20 -14
- data/lib/license_finder/cli.rb +4 -3
- data/lib/license_finder/configuration.rb +34 -0
- data/lib/license_finder/dependency.rb +27 -22
- data/lib/license_finder/dependency_list.rb +35 -13
- data/lib/license_finder/license.rb +11 -1
- data/lib/license_finder/license/apache2.rb +8 -0
- data/lib/license_finder/license/bsd.rb +2 -0
- data/lib/license_finder/license/gplv2.rb +2 -0
- data/lib/license_finder/license/isc.rb +1 -0
- data/lib/license_finder/license/lgpl.rb +1 -0
- data/lib/license_finder/license/mit.rb +4 -1
- data/lib/license_finder/license/new_bsd.rb +3 -0
- data/lib/license_finder/license/ruby.rb +2 -2
- data/lib/license_finder/license/simplified_bsd.rb +3 -0
- data/lib/license_finder/license_url.rb +10 -0
- data/lib/license_finder/possible_license_file.rb +2 -2
- data/lib/license_finder/railtie.rb +1 -3
- data/lib/license_finder/reporter.rb +51 -0
- data/lib/license_finder/viewable.rb +31 -0
- data/lib/tasks/license_finder.rake +3 -28
- data/lib/templates/dependency.html.erb +54 -0
- data/lib/templates/dependency_list.html.erb +38 -0
- data/license_finder.gemspec +12 -4
- data/spec/lib/license_finder/bundled_gem_spec.rb +5 -3
- data/spec/lib/license_finder/dependency_list_spec.rb +54 -9
- data/spec/lib/license_finder/dependency_spec.rb +93 -57
- data/spec/lib/license_finder/license/apache_spec.rb +2 -2
- data/spec/lib/license_finder/license/mit_spec.rb +1 -1
- data/spec/lib/license_finder/license_spec.rb +14 -0
- data/spec/lib/license_finder/license_url_spec.rb +20 -0
- data/spec/lib/license_finder/reporter_spec.rb +5 -0
- data/spec/lib/license_finder_spec.rb +2 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/license_examples.rb +6 -0
- metadata +68 -33
- data/features/executables/license_finder.feature +0 -19
- data/features/rake_tasks/action_items.feature +0 -27
- data/features/rake_tasks/action_items_ok.feature +0 -23
- data/features/rake_tasks/generate_dependencies.feature +0 -62
- data/features/rake_tasks/init.feature +0 -26
- data/features/rake_tasks/regressions.feature +0 -18
- data/lib/license_finder/bundler_dependency_query.rb +0 -51
- data/lib/license_finder/finder.rb +0 -39
- data/lib/license_finder/license/apache.rb +0 -5
- data/spec/lib/license_finder/finder_spec.rb +0 -36
@@ -0,0 +1,27 @@
|
|
1
|
+
Feature: Text Report
|
2
|
+
So that I can easily view a report outlining my application dependencies and licenses
|
3
|
+
As a non-technical application product owner
|
4
|
+
I want license finder to generate an easy-to-understand text report
|
5
|
+
|
6
|
+
Scenario: Viewing dependencies
|
7
|
+
Given I have an app with license finder
|
8
|
+
And my application depends on a gem "descriptive_gem" with:
|
9
|
+
| license | version |
|
10
|
+
| MIT | 1.1.1 |
|
11
|
+
When I run "license_finder"
|
12
|
+
Then I should see the file "dependencies.txt" containing:
|
13
|
+
"""
|
14
|
+
descriptive_gem, 1.1.1, MIT
|
15
|
+
"""
|
16
|
+
|
17
|
+
Scenario: Viewing dependencies after multiple runs
|
18
|
+
Given I have an app with license finder
|
19
|
+
And my application depends on a gem "descriptive_gem" with:
|
20
|
+
| license | version |
|
21
|
+
| MIT | 1.1.1 |
|
22
|
+
When I run "license_finder"
|
23
|
+
And I run "license_finder"
|
24
|
+
Then I should see the file "dependencies.txt" containing:
|
25
|
+
"""
|
26
|
+
descriptive_gem, 1.1.1, MIT
|
27
|
+
"""
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/license_finder.rb
CHANGED
@@ -4,30 +4,17 @@ require 'yaml'
|
|
4
4
|
module LicenseFinder
|
5
5
|
ROOT_PATH = Pathname.new(__FILE__).dirname
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@whitelist = config['whitelist'] || []
|
19
|
-
@ignore_groups = (config["ignore_groups"] || []).map(&:to_sym)
|
20
|
-
@dependencies_dir = config['dependencies_file_dir'] || '.'
|
21
|
-
end
|
22
|
-
|
23
|
-
def dependencies_yaml
|
24
|
-
File.join(dependencies_dir, "dependencies.yml")
|
25
|
-
end
|
26
|
-
|
27
|
-
def dependencies_text
|
28
|
-
File.join(dependencies_dir, "dependencies.txt")
|
29
|
-
end
|
30
|
-
end
|
7
|
+
autoload :Bundle, 'license_finder/bundle'
|
8
|
+
autoload :BundledGem, 'license_finder/bundled_gem'
|
9
|
+
autoload :CLI, 'license_finder/cli'
|
10
|
+
autoload :Configuration, 'license_finder/configuration'
|
11
|
+
autoload :Dependency, 'license_finder/dependency'
|
12
|
+
autoload :DependencyList, 'license_finder/dependency_list'
|
13
|
+
autoload :License, 'license_finder/license'
|
14
|
+
autoload :LicenseUrl, 'license_finder/license_url'
|
15
|
+
autoload :PossibleLicenseFile, 'license_finder/possible_license_file'
|
16
|
+
autoload :Reporter, 'license_finder/reporter'
|
17
|
+
autoload :Viewable, 'license_finder/viewable'
|
31
18
|
|
32
19
|
def self.config
|
33
20
|
@config ||= Configuration.new
|
@@ -39,11 +26,3 @@ module LicenseFinder
|
|
39
26
|
end
|
40
27
|
|
41
28
|
require 'license_finder/railtie' if defined?(Rails)
|
42
|
-
require 'license_finder/bundler_dependency_query'
|
43
|
-
require 'license_finder/finder'
|
44
|
-
require 'license_finder/bundled_gem'
|
45
|
-
require 'license_finder/license'
|
46
|
-
require 'license_finder/possible_license_file'
|
47
|
-
require 'license_finder/dependency'
|
48
|
-
require 'license_finder/dependency_list'
|
49
|
-
require 'license_finder/cli'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module LicenseFinder
|
2
|
+
class Bundle
|
3
|
+
def gems
|
4
|
+
definition.specs_for(included_groups).map do |spec|
|
5
|
+
dependency = dependencies.detect { |dep| dep.name == spec.name }
|
6
|
+
|
7
|
+
BundledGem.new(spec, dependency)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def definition
|
14
|
+
@definition ||= Bundler::Definition.build(gemfile_path, lockfile_path, nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def dependencies
|
18
|
+
@dependencies ||= definition.dependencies
|
19
|
+
end
|
20
|
+
|
21
|
+
def included_groups
|
22
|
+
definition.groups - LicenseFinder.config.ignore_groups
|
23
|
+
end
|
24
|
+
|
25
|
+
def gemfile_path
|
26
|
+
Pathname.new("Gemfile").expand_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def lockfile_path
|
30
|
+
gemfile_path.dirname.join('Gemfile.lock')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,36 +1,38 @@
|
|
1
1
|
module LicenseFinder
|
2
2
|
class BundledGem
|
3
|
-
LICENSE_FILE_NAMES =
|
4
|
-
README_FILE_NAMES =
|
3
|
+
LICENSE_FILE_NAMES = %w(LICENSE License Licence COPYING README Readme ReadMe)
|
4
|
+
README_FILE_NAMES = %w(README Readme ReadMe)
|
5
5
|
|
6
|
-
def initialize(spec)
|
6
|
+
def initialize(spec, bundler_dependency = nil)
|
7
7
|
@spec = spec
|
8
|
+
@bundler_dependency = bundler_dependency
|
8
9
|
end
|
9
10
|
|
10
|
-
attr_reader :spec
|
11
|
-
|
12
11
|
def name
|
13
12
|
"#{dependency_name} #{dependency_version}"
|
14
13
|
end
|
15
14
|
|
16
15
|
def dependency_name
|
17
|
-
spec.name
|
16
|
+
@spec.name
|
18
17
|
end
|
19
18
|
|
20
19
|
def dependency_version
|
21
|
-
spec.version.to_s
|
20
|
+
@spec.version.to_s
|
22
21
|
end
|
23
22
|
|
24
|
-
def
|
25
|
-
@dependency ||= Dependency.new(
|
23
|
+
def to_dependency
|
24
|
+
@dependency ||= LicenseFinder::Dependency.new(
|
26
25
|
'name' => @spec.name,
|
27
26
|
'version' => @spec.version.to_s,
|
28
27
|
'license' => determine_license,
|
29
28
|
'license_files' => license_files.map(&:full_file_path),
|
30
29
|
'readme_files' => readme_files.map(&:full_file_path),
|
31
30
|
'source' => 'bundle',
|
31
|
+
'bundler_groups' => (@bundler_dependency.groups if @bundler_dependency),
|
32
32
|
'summary' => @spec.summary,
|
33
|
-
'description' => @spec.description
|
33
|
+
'description' => @spec.description,
|
34
|
+
'homepage' => @spec.homepage,
|
35
|
+
'children' => @spec.dependencies
|
34
36
|
)
|
35
37
|
end
|
36
38
|
|
@@ -41,7 +43,7 @@ module LicenseFinder
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def license_files
|
44
|
-
paths_with_license_names =
|
46
|
+
paths_with_license_names = find_matching_files(LICENSE_FILE_NAMES)
|
45
47
|
paths_for_license_files = paths_with_license_names.map do |path|
|
46
48
|
File.directory?(path) ? paths_for_files_in_license_directory(path) : path
|
47
49
|
end.flatten.uniq
|
@@ -49,13 +51,13 @@ module LicenseFinder
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def readme_files
|
52
|
-
|
53
|
-
get_file_for_path
|
54
|
+
find_matching_files(README_FILE_NAMES).map do |path|
|
55
|
+
get_file_for_path(path)
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
57
59
|
def install_path
|
58
|
-
spec.full_gem_path
|
60
|
+
@spec.full_gem_path
|
59
61
|
end
|
60
62
|
|
61
63
|
def sort_order
|
@@ -64,6 +66,10 @@ module LicenseFinder
|
|
64
66
|
|
65
67
|
private
|
66
68
|
|
69
|
+
def find_matching_files(names)
|
70
|
+
Dir.glob(File.join(install_path, '**', "*{#{names.join(',')}}*"))
|
71
|
+
end
|
72
|
+
|
67
73
|
def get_file_for_path(path)
|
68
74
|
PossibleLicenseFile.new(install_path, path)
|
69
75
|
end
|
data/lib/license_finder/cli.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module LicenseFinder
|
2
|
-
|
2
|
+
module CLI
|
3
|
+
extend self
|
4
|
+
|
3
5
|
def check_for_action_items
|
4
|
-
found = LicenseFinder::
|
6
|
+
found = LicenseFinder::Reporter.new.action_items
|
5
7
|
|
6
8
|
if found.size == 0
|
7
9
|
puts "All gems are approved for use"
|
8
|
-
exit 0
|
9
10
|
else
|
10
11
|
puts "Dependencies that need approval:"
|
11
12
|
puts found
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module LicenseFinder
|
2
|
+
class Configuration
|
3
|
+
attr_reader :whitelist, :ignore_groups, :dependencies_dir
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
config = {}
|
7
|
+
|
8
|
+
if File.exists?(config_file_path)
|
9
|
+
yaml = File.open(config_file_path).readlines.join
|
10
|
+
config = YAML.load(yaml)
|
11
|
+
end
|
12
|
+
|
13
|
+
@whitelist = config['whitelist'] || []
|
14
|
+
@ignore_groups = (config["ignore_groups"] || []).map(&:to_sym)
|
15
|
+
@dependencies_dir = config['dependencies_file_dir'] || '.'
|
16
|
+
end
|
17
|
+
|
18
|
+
def config_file_path
|
19
|
+
File.join('.', 'config', 'license_finder.yml')
|
20
|
+
end
|
21
|
+
|
22
|
+
def dependencies_yaml
|
23
|
+
File.join(dependencies_dir, "dependencies.yml")
|
24
|
+
end
|
25
|
+
|
26
|
+
def dependencies_text
|
27
|
+
File.join(dependencies_dir, "dependencies.txt")
|
28
|
+
end
|
29
|
+
|
30
|
+
def dependencies_html
|
31
|
+
File.join(dependencies_dir, "dependencies.html")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -3,8 +3,10 @@ require "erb"
|
|
3
3
|
|
4
4
|
module LicenseFinder
|
5
5
|
class Dependency
|
6
|
+
include Viewable
|
7
|
+
|
6
8
|
attr_accessor :name, :version, :license, :approved, :license_url, :notes, :license_files,
|
7
|
-
:readme_files, :source, :bundler_groups
|
9
|
+
:readme_files, :source, :bundler_groups, :homepage, :children, :parents
|
8
10
|
|
9
11
|
attr_reader :summary, :description
|
10
12
|
|
@@ -21,13 +23,19 @@ module LicenseFinder
|
|
21
23
|
@version = attributes['version']
|
22
24
|
@license = attributes['license']
|
23
25
|
@approved = attributes['approved'] || LicenseFinder.config.whitelist.include?(attributes['license'])
|
24
|
-
@license_url = attributes['license_url'] || ''
|
25
26
|
@notes = attributes['notes'] || ''
|
26
27
|
@license_files = attributes['license_files'] || []
|
27
28
|
@readme_files = attributes['readme_files'] || []
|
28
29
|
@bundler_groups = attributes['bundler_groups'] || []
|
29
30
|
@summary = attributes['summary']
|
30
31
|
@description = attributes['description']
|
32
|
+
@homepage = attributes['homepage']
|
33
|
+
@children = attributes.fetch('children', [])
|
34
|
+
@parents = attributes.fetch('parents', [])
|
35
|
+
end
|
36
|
+
|
37
|
+
def license_url
|
38
|
+
LicenseFinder::LicenseUrl.find_by_name license
|
31
39
|
end
|
32
40
|
|
33
41
|
def merge(other)
|
@@ -44,6 +52,9 @@ module LicenseFinder
|
|
44
52
|
'summary' => other.summary,
|
45
53
|
'description' => other.description,
|
46
54
|
'bundler_groups' => other.bundler_groups,
|
55
|
+
'homepage' => other.homepage,
|
56
|
+
'children' => other.children,
|
57
|
+
'parents' => other.parents
|
47
58
|
)
|
48
59
|
|
49
60
|
case other.license
|
@@ -66,6 +77,7 @@ module LicenseFinder
|
|
66
77
|
'approved' => approved,
|
67
78
|
'source' => source,
|
68
79
|
'license_url' => license_url,
|
80
|
+
'homepage' => homepage,
|
69
81
|
'notes' => notes,
|
70
82
|
'license_files' => nil,
|
71
83
|
'readme_files' => nil
|
@@ -86,28 +98,21 @@ module LicenseFinder
|
|
86
98
|
attrs
|
87
99
|
end
|
88
100
|
|
89
|
-
def
|
90
|
-
|
101
|
+
def to_s
|
102
|
+
[name, version, license].join ", "
|
91
103
|
end
|
92
104
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
<% end %>
|
105
|
-
<% end%>
|
106
|
-
TEMPLATE
|
107
|
-
|
108
|
-
attributes = ["#{name} #{version}".strip, license, license_url, summary, description, bundler_groups].flatten.compact.reject {|a| a == ""}
|
109
|
-
|
110
|
-
template.result(binding).gsub(/(^|\n)\s*(\n|$)/, '\1')
|
105
|
+
private
|
106
|
+
|
107
|
+
def constantize(string)
|
108
|
+
names = string.split('::')
|
109
|
+
names.shift if names.empty? || names.first.empty?
|
110
|
+
|
111
|
+
constant = Object
|
112
|
+
names.each do |name|
|
113
|
+
constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
|
114
|
+
end
|
115
|
+
constant
|
111
116
|
end
|
112
117
|
end
|
113
118
|
end
|
@@ -1,19 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module LicenseFinder
|
2
4
|
class DependencyList
|
5
|
+
include Viewable
|
3
6
|
|
4
7
|
attr_reader :dependencies
|
5
8
|
|
6
9
|
def self.from_bundler
|
7
|
-
new(
|
10
|
+
dep_list = new(Bundle.new.gems.map(&:to_dependency))
|
11
|
+
setup_parents_of_dependencies(dep_list)
|
12
|
+
dep_list
|
8
13
|
end
|
9
14
|
|
10
|
-
def
|
11
|
-
|
15
|
+
def self.setup_parents_of_dependencies(dep_list)
|
16
|
+
dependency_index = {}
|
17
|
+
dep_list.dependencies.each do |dep|
|
18
|
+
dependency_index[dep.name] = dep
|
19
|
+
end
|
20
|
+
|
21
|
+
dep_list.dependencies.each do |dep|
|
22
|
+
dep.children.each do |child_dep|
|
23
|
+
license_finder_dependency = dependency_index[child_dep.name]
|
24
|
+
license_finder_dependency.parents << dep if license_finder_dependency
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.from_yaml(yaml)
|
30
|
+
deps = YAML.load(yaml)
|
31
|
+
new(deps.map { |attrs| Dependency.from_hash(attrs) })
|
12
32
|
end
|
13
33
|
|
14
|
-
def
|
15
|
-
|
16
|
-
new(deps.map { |dhash| Dependency.from_hash(dhash) })
|
34
|
+
def initialize(dependencies)
|
35
|
+
@dependencies = dependencies
|
17
36
|
end
|
18
37
|
|
19
38
|
def merge(new_list)
|
@@ -36,23 +55,26 @@ module LicenseFinder
|
|
36
55
|
sorted_dependencies.map(&:as_yaml)
|
37
56
|
end
|
38
57
|
|
39
|
-
def to_yaml
|
40
|
-
as_yaml.to_yaml
|
41
|
-
end
|
42
|
-
|
43
58
|
def to_s
|
44
|
-
sorted_dependencies.map(&:to_s).join
|
59
|
+
sorted_dependencies.map(&:to_s).join("\n")
|
45
60
|
end
|
46
61
|
|
47
62
|
def action_items
|
48
|
-
sorted_dependencies.reject(&:approved).map(&:to_s).join
|
63
|
+
sorted_dependencies.reject(&:approved).map(&:to_s).join "\n"
|
49
64
|
end
|
50
65
|
|
51
66
|
private
|
52
67
|
|
68
|
+
def unapproved_dependencies
|
69
|
+
dependencies.reject(&:approved)
|
70
|
+
end
|
71
|
+
|
53
72
|
def sorted_dependencies
|
54
73
|
dependencies.sort_by(&:name)
|
55
74
|
end
|
75
|
+
|
76
|
+
def grouped_dependencies
|
77
|
+
dependencies.group_by(&:license).sort_by { |_, group| group.size }.reverse
|
78
|
+
end
|
56
79
|
end
|
57
80
|
end
|
58
|
-
|