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.
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
-