license_finder 0.5.0 → 0.6.0
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/.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
|
-
|