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.
Files changed (68) hide show
  1. data/.travis.yml +22 -0
  2. data/README.markdown +56 -92
  3. data/Rakefile +1 -1
  4. data/bin/license_finder +1 -1
  5. data/features/approve_dependencies.feature +49 -0
  6. data/features/html_report.feature +48 -0
  7. data/features/license_finder.feature +36 -0
  8. data/features/license_finder_rake_task.feature +36 -0
  9. data/features/rails_rake.feature +9 -0
  10. data/features/step_definitions/steps.rb +78 -31
  11. data/features/text_report.feature +27 -0
  12. data/lib/{templates/Apache.txt → data/licenses/Apache2.txt} +0 -0
  13. data/lib/{templates → data/licenses}/BSD.txt +0 -0
  14. data/lib/{templates → data/licenses}/GPLv2.txt +0 -0
  15. data/lib/{templates → data/licenses}/ISC.txt +0 -0
  16. data/lib/{templates → data/licenses}/LGPL.txt +0 -0
  17. data/lib/{templates → data/licenses}/MIT.txt +0 -0
  18. data/lib/{templates → data/licenses}/NewBSD.txt +0 -0
  19. data/lib/{templates → data/licenses}/Ruby.txt +0 -0
  20. data/lib/{templates → data/licenses}/SimplifiedBSD.txt +0 -0
  21. data/lib/license_finder.rb +11 -32
  22. data/lib/license_finder/bundle.rb +33 -0
  23. data/lib/license_finder/bundled_gem.rb +20 -14
  24. data/lib/license_finder/cli.rb +4 -3
  25. data/lib/license_finder/configuration.rb +34 -0
  26. data/lib/license_finder/dependency.rb +27 -22
  27. data/lib/license_finder/dependency_list.rb +35 -13
  28. data/lib/license_finder/license.rb +11 -1
  29. data/lib/license_finder/license/apache2.rb +8 -0
  30. data/lib/license_finder/license/bsd.rb +2 -0
  31. data/lib/license_finder/license/gplv2.rb +2 -0
  32. data/lib/license_finder/license/isc.rb +1 -0
  33. data/lib/license_finder/license/lgpl.rb +1 -0
  34. data/lib/license_finder/license/mit.rb +4 -1
  35. data/lib/license_finder/license/new_bsd.rb +3 -0
  36. data/lib/license_finder/license/ruby.rb +2 -2
  37. data/lib/license_finder/license/simplified_bsd.rb +3 -0
  38. data/lib/license_finder/license_url.rb +10 -0
  39. data/lib/license_finder/possible_license_file.rb +2 -2
  40. data/lib/license_finder/railtie.rb +1 -3
  41. data/lib/license_finder/reporter.rb +51 -0
  42. data/lib/license_finder/viewable.rb +31 -0
  43. data/lib/tasks/license_finder.rake +3 -28
  44. data/lib/templates/dependency.html.erb +54 -0
  45. data/lib/templates/dependency_list.html.erb +38 -0
  46. data/license_finder.gemspec +12 -4
  47. data/spec/lib/license_finder/bundled_gem_spec.rb +5 -3
  48. data/spec/lib/license_finder/dependency_list_spec.rb +54 -9
  49. data/spec/lib/license_finder/dependency_spec.rb +93 -57
  50. data/spec/lib/license_finder/license/apache_spec.rb +2 -2
  51. data/spec/lib/license_finder/license/mit_spec.rb +1 -1
  52. data/spec/lib/license_finder/license_spec.rb +14 -0
  53. data/spec/lib/license_finder/license_url_spec.rb +20 -0
  54. data/spec/lib/license_finder/reporter_spec.rb +5 -0
  55. data/spec/lib/license_finder_spec.rb +2 -0
  56. data/spec/spec_helper.rb +0 -1
  57. data/spec/support/license_examples.rb +6 -0
  58. metadata +68 -33
  59. data/features/executables/license_finder.feature +0 -19
  60. data/features/rake_tasks/action_items.feature +0 -27
  61. data/features/rake_tasks/action_items_ok.feature +0 -23
  62. data/features/rake_tasks/generate_dependencies.feature +0 -62
  63. data/features/rake_tasks/init.feature +0 -26
  64. data/features/rake_tasks/regressions.feature +0 -18
  65. data/lib/license_finder/bundler_dependency_query.rb +0 -51
  66. data/lib/license_finder/finder.rb +0 -39
  67. data/lib/license_finder/license/apache.rb +0 -5
  68. 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
@@ -4,30 +4,17 @@ require 'yaml'
4
4
  module LicenseFinder
5
5
  ROOT_PATH = Pathname.new(__FILE__).dirname
6
6
 
7
- class Configuration
8
- attr_reader :whitelist, :ignore_groups, :dependencies_dir
9
-
10
- def initialize
11
- config = {}
12
-
13
- if File.exists?('./config/license_finder.yml')
14
- yaml = File.open('./config/license_finder.yml').readlines.join
15
- config = YAML.load(yaml)
16
- end
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 = '*{LICENSE,License,Licence,COPYING,README,Readme,ReadMe}*' # follows Dir.glob format
4
- README_FILE_NAMES = '*{README,Readme,ReadMe}*' # follows Dir.glob format
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 dependency
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 = Dir.glob(File.join(install_path, '**', LICENSE_FILE_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
- Dir.glob(File.join(install_path, '**', README_FILE_NAMES)).map do |path|
53
- get_file_for_path 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
@@ -1,11 +1,12 @@
1
1
  module LicenseFinder
2
- class CLI
2
+ module CLI
3
+ extend self
4
+
3
5
  def check_for_action_items
4
- found = LicenseFinder::Finder.new.action_items
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 to_yaml
90
- as_yaml.to_yaml
101
+ def to_s
102
+ [name, version, license].join ", "
91
103
  end
92
104
 
93
- def to_s
94
- template = ERB.new <<-TEMPLATE
95
- <%= attributes.join(", ") %>
96
- <% if license == 'other' %>
97
- <% unless license_files.empty? %>
98
- license files:
99
- <%= license_files.join("\n ") %>
100
- <% end %>
101
- <% unless readme_files.empty? %>
102
- readme files:
103
- <%= readme_files.join("\n ") %>
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(BundlerDependencyQuery.new.dependencies)
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 initialize(dependencies)
11
- @dependencies = dependencies
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 self.from_yaml(yml)
15
- deps = YAML.load(yml)
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
-