licensed 2.11.0 → 2.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9cb9d80097e4329d3aa276faf53b72cac7fed2c2f4c09edc500bc627fb8d942b
4
- data.tar.gz: f2ba113cfac5f807980f44a7d60a40dd6c946c85a351bf8161854b72d715d625
3
+ metadata.gz: a4477f07cae2650a7d8679a9042f73a7d14d8de019088be22d09f30e0f8af4c2
4
+ data.tar.gz: b4cbd8769c1f98b1a0729e5d603ff08c15d2d5c5e4e8e029cd3bce7f69f395c1
5
5
  SHA512:
6
- metadata.gz: dcdc95e2d512dbf8f9e84f76409f4d94b93ae3bdf95d17fa4b668f04e996cdcda340c5e7f09dd499c509b122e92cfc90d58838f33df24d690fd4ae1b759550b0
7
- data.tar.gz: bba8ba26db299965d6fc7e2d783060d827e5f45cd7f1a287414f63c39298b39dfb6739beebe46d152e6619830705a8abf822a33ce01d94335fc195596a65e6cb
6
+ metadata.gz: 83e7612e7a1fe2dbb77d48893c68db036630a45cdbc37f38f6630be0380231d9ac7fc0d37298d3a8a349d4bd43eb1dad64b7ec26a4b8d795806fb682091d94b7
7
+ data.tar.gz: 26e4fed8cede2d4de43fc511a85a82507dcc0cbcc9a66537d39a189d533a7cfbb22fdf2be5ad242ae72f4943fde6676c23b0bdcdf906beeecef813369177c158
@@ -116,7 +116,7 @@ jobs:
116
116
  runs-on: ubuntu-latest
117
117
  strategy:
118
118
  matrix:
119
- ruby: [ 2.4.x, 2.5.x, 2.6.x ]
119
+ ruby: [ 2.4.x, 2.5.x, 2.6.x, 2.7.x ]
120
120
  steps:
121
121
  - uses: actions/checkout@v2
122
122
  - name: Set up Ruby
@@ -6,6 +6,45 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.13.0
10
+ 2020-09-23
11
+
12
+ ### Added
13
+ - `status` command results can be output in YAML and JSON formats (:tada: @julianvilas https://github.com/github/licensed/pull/303)
14
+
15
+ ### Fixed
16
+ - `licensed` no longer crashes when parsing invalid YAML from cached records (https://github.com/github/licensed/pull/306)
17
+ - NPM source will no longer crash when invalid JSON is returned from npm CLI calls (https://github.com/github/licensed/pull/300)
18
+ - Bundler source is fixed to work properly with `gems.rb` lockfiles (https://github.com/github/licensed/pull/299)
19
+
20
+ ## 2.12.2
21
+ 2020-07-07
22
+
23
+ ### Changed
24
+ - Cleaned up ruby 2.7 warnings (:tada: @jurre https://github.com/github/licensed/pull/292)
25
+ - Cleaned up additional warnings in tests (https://github.com/github/licensed/pull/293)
26
+
27
+ ## 2.12.1
28
+ 2020-06-30
29
+
30
+ ### Fixed
31
+ - `licensed` no longer exits an error code when using the `--sources` CLI argument (https://github.com/github/licensed/pull/290)
32
+
33
+ ## 2.12.0
34
+ 2020-06-19
35
+
36
+ ### Added
37
+ - `--sources` argument for cache, list, status and notices commands to filter running sources (https://github.com/github/licensed/pull/287)
38
+
39
+ ### Fixed
40
+ - `cache` command will not remove files outside of enabled source cache paths (https://github.com/github/licensed/pull/287)
41
+
42
+ ## 2.11.1
43
+ 2020-06-09
44
+
45
+ ### Fixed
46
+ - `notices` command properly reads cached dependency notices contents (https://github.com/github/licensed/pull/283)
47
+
9
48
  ## 2.11.0
10
49
  2020-06-02
11
50
 
@@ -312,4 +351,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
312
351
 
313
352
  Initial release :tada:
314
353
 
315
- [Unreleased]: https://github.com/github/licensed/compare/2.11.0...HEAD
354
+ [Unreleased]: https://github.com/github/licensed/compare/2.13.0...HEAD
@@ -6,10 +6,14 @@ Run `licensed -h` to see help content for running licensed commands.
6
6
 
7
7
  Running the list command finds the dependencies for all sources in all configured applications. No additional actions are taken on each dependency.
8
8
 
9
+ An optional `--sources` flag can be given to limit which dependency sources are run. This is a filter over sources that are enabled via the licensed configuration file and cannot be used to run licensed with a disabled source.
10
+
9
11
  ## `cache`
10
12
 
11
13
  The cache command finds all dependencies and ensures that each dependency has an up-to-date cached record.
12
14
 
15
+ An optional `--sources` flag can be given to limit which dependency sources are run. This is a filter over sources that are enabled via the licensed configuration file and cannot be used to run licensed with a disabled source.
16
+
13
17
  Dependency records will be saved if:
14
18
  1. The `force` option is set
15
19
  2. No cached record is found
@@ -22,6 +26,8 @@ After the cache command is run, any cached records that don't match up to a curr
22
26
 
23
27
  The status command finds all dependencies and checks whether each dependency has a valid cached record.
24
28
 
29
+ An optional `--sources` flag can be given to limit which dependency sources are run. This is a filter over sources that are enabled via the licensed configuration file and cannot be used to run licensed with a disabled source.
30
+
25
31
  A dependency will fail the status checks if:
26
32
  1. No cached record is found
27
33
  2. The cached record's version is different than the current dependency's version
@@ -35,6 +41,8 @@ A dependency will fail the status checks if:
35
41
 
36
42
  Outputs license and notice text for all dependencies in each app into a `NOTICE` file in the app's `cache_path`. If an app uses a shared cache path, the file name will contain the app name as well, e.g. `NOTICE.my_app`.
37
43
 
44
+ An optional `--sources` flag can be given to limit which dependency sources are run. This is a filter over sources that are enabled via the licensed configuration file and cannot be used to run licensed with a disabled source.
45
+
38
46
  The `NOTICE` file contents are retrieved from cached records, with the assumption that cached records have already been reviewed in a compliance workflow.
39
47
 
40
48
  ## `env`
@@ -10,29 +10,40 @@ module Licensed
10
10
  desc: "Overwrite licenses even if version has not changed."
11
11
  method_option :config, aliases: "-c", type: :string,
12
12
  desc: "Path to licensed configuration file"
13
+ method_option :sources, aliases: "-s", type: :array,
14
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
13
15
  def cache
14
- run Licensed::Commands::Cache.new(config: config), force: options[:force]
16
+ run Licensed::Commands::Cache.new(config: config),
17
+ force: options[:force], sources: options[:sources]
15
18
  end
16
19
 
17
20
  desc "status", "Check status of dependencies' cached licenses"
21
+ method_option :format, enum: ["yaml", "json"],
22
+ desc: "Output format"
18
23
  method_option :config, aliases: "-c", type: :string,
19
24
  desc: "Path to licensed configuration file"
25
+ method_option :sources, aliases: "-s", type: :array,
26
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
20
27
  def status
21
- run Licensed::Commands::Status.new(config: config)
28
+ run Licensed::Commands::Status.new(config: config), sources: options[:sources], reporter: options[:format]
22
29
  end
23
30
 
24
31
  desc "list", "List dependencies"
25
32
  method_option :config, aliases: "-c", type: :string,
26
33
  desc: "Path to licensed configuration file"
34
+ method_option :sources, aliases: "-s", type: :array,
35
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
27
36
  def list
28
- run Licensed::Commands::List.new(config: config)
37
+ run Licensed::Commands::List.new(config: config), sources: options[:sources]
29
38
  end
30
39
 
31
40
  desc "notices", "Generate a NOTICE file from cached records"
32
41
  method_option :config, aliases: "-c", type: :string,
33
42
  desc: "Path to licensed configuration file"
43
+ method_option :sources, aliases: "-s", type: :array,
44
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
34
45
  def notices
35
- run Licensed::Commands::Notices.new(config: config)
46
+ run Licensed::Commands::Notices.new(config: config), sources: options[:sources]
36
47
  end
37
48
 
38
49
  map "-v" => :version
@@ -48,7 +59,7 @@ module Licensed
48
59
  method_option :config, aliases: "-c", type: :string,
49
60
  desc: "Path to licensed configuration file"
50
61
  def env
51
- run Licensed::Commands::Environment.new(config: config), format: options[:format]
62
+ run Licensed::Commands::Environment.new(config: config), reporter: options[:format]
52
63
  end
53
64
 
54
65
  desc "migrate", "Migrate from a previous version of licensed"
@@ -87,7 +98,7 @@ module Licensed
87
98
  end
88
99
 
89
100
  def run(command, **args)
90
- exit command.run(args)
101
+ exit command.run(**args)
91
102
  end
92
103
  end
93
104
  end
@@ -2,12 +2,12 @@
2
2
  module Licensed
3
3
  module Commands
4
4
  class Cache < Command
5
- # Create a reporter to use during a command run
5
+ # Returns the default reporter to use during the command run
6
6
  #
7
7
  # options - The options the command was run with
8
8
  #
9
- # Raises a Licensed::Reporters::CacheReporter
10
- def create_reporter(options)
9
+ # Returns a Licensed::Reporters::CacheReporter
10
+ def default_reporter(options)
11
11
  Licensed::Reporters::CacheReporter.new
12
12
  end
13
13
 
@@ -32,19 +32,26 @@ module Licensed
32
32
 
33
33
  protected
34
34
 
35
- # Run the command for all enabled sources for an application configuration,
35
+ # Run the command for all enumerated dependencies found in a dependency source,
36
36
  # recording results in a report.
37
+ # Enumerating dependencies in the source is skipped if a :sources option
38
+ # is provided and the evaluated `source.class.type` is not in the :sources values
37
39
  #
38
- # app - An application configuration
40
+ # app - The application configuration for the source
41
+ # source - A dependency source enumerator
39
42
  #
40
- # Returns whether the command succeeded for the application.
41
- def run_app(app)
42
- result = super
43
-
44
- # add the full cache path to the list of cache paths evaluted during this run
45
- cache_paths << app.cache_path
43
+ # Returns whether the command succeeded for the dependency source enumerator
44
+ def run_source(app, source)
45
+ super do |report|
46
+ if Array(options[:sources]).any? && !options[:sources].include?(source.class.type)
47
+ report.warnings << "skipped source"
48
+ next :skip
49
+ end
46
50
 
47
- result
51
+ # add the full cache path to the list of cache paths
52
+ # that should be cleaned up after the command run
53
+ cache_paths << app.cache_path.join(source.class.type)
54
+ end
48
55
  end
49
56
 
50
57
  # Cache dependency record data.
@@ -21,7 +21,9 @@ module Licensed
21
21
  begin
22
22
  result = reporter.report_run(self) do |report|
23
23
  # allow additional report data to be given by commands
24
- yield report if block_given?
24
+ if block_given?
25
+ next true if (yield report) == :skip
26
+ end
25
27
 
26
28
  config.apps.sort_by { |app| app["name"] }
27
29
  .map { |app| run_app(app) }
@@ -35,13 +37,29 @@ module Licensed
35
37
  result
36
38
  end
37
39
 
38
- # Create a reporter to use during a command run
40
+ # Creates a reporter to use during a command run
39
41
  #
40
42
  # options - The options the command was run with
41
43
  #
42
- # Raises an error
44
+ # Returns the reporter to use during the command run
43
45
  def create_reporter(options)
44
- raise "`create_reporter` must be implemented by commands"
46
+ return options[:reporter] if options[:reporter].is_a?(Licensed::Reporters::Reporter)
47
+
48
+ if options[:reporter].is_a?(String)
49
+ klass = "#{options[:reporter].capitalize}Reporter"
50
+ return Licensed::Reporters.const_get(klass).new if Licensed::Reporters.const_defined?(klass)
51
+ end
52
+
53
+ default_reporter(options)
54
+ end
55
+
56
+ # Returns the default reporter to use during the command run
57
+ #
58
+ # options - The options the command was run with
59
+ #
60
+ # Raises an error
61
+ def default_reporter(options)
62
+ raise "`default_reporter` must be implemented by commands"
45
63
  end
46
64
 
47
65
  protected
@@ -57,7 +75,9 @@ module Licensed
57
75
  Dir.chdir app.source_path do
58
76
  begin
59
77
  # allow additional report data to be given by commands
60
- yield report if block_given?
78
+ if block_given?
79
+ next true if (yield report) == :skip
80
+ end
61
81
 
62
82
  app.sources.select(&:enabled?)
63
83
  .sort_by { |source| source.class.type }
@@ -81,7 +101,9 @@ module Licensed
81
101
  reporter.report_source(source) do |report|
82
102
  begin
83
103
  # allow additional report data to be given by commands
84
- yield report if block_given?
104
+ if block_given?
105
+ next true if (yield report) == :skip
106
+ end
85
107
 
86
108
  source.dependencies.sort_by { |dependency| dependency.name }
87
109
  .map { |dependency| run_dependency(app, source, dependency) }
@@ -114,10 +136,12 @@ module Licensed
114
136
 
115
137
  begin
116
138
  # allow additional report data to be given by commands
117
- yield report if block_given?
139
+ if block_given?
140
+ next true if (yield report) == :skip
141
+ end
118
142
 
119
143
  evaluate_dependency(app, source, dependency, report)
120
- rescue Licensed::Shell::Error => err
144
+ rescue Licensed::DependencyRecord::Error, Licensed::Shell::Error => err
121
145
  report.errors << err.message
122
146
  false
123
147
  end
@@ -35,13 +35,13 @@ module Licensed
35
35
  end
36
36
  end
37
37
 
38
- def create_reporter(options)
39
- case options[:format]
40
- when "json"
41
- Licensed::Reporters::JsonReporter.new
42
- else
43
- Licensed::Reporters::YamlReporter.new
44
- end
38
+ # Returns the default reporter to use during the command run
39
+ #
40
+ # options - The options the command was run with
41
+ #
42
+ # Returns a Licensed::Reporters::StatusReporter
43
+ def default_reporter(options)
44
+ Licensed::Reporters::YamlReporter.new
45
45
  end
46
46
 
47
47
  protected
@@ -2,17 +2,36 @@
2
2
  module Licensed
3
3
  module Commands
4
4
  class List < Command
5
- # Create a reporter to use during a command run
5
+ # Returns the default reporter to use during the command run
6
6
  #
7
7
  # options - The options the command was run with
8
8
  #
9
9
  # Returns a Licensed::Reporters::ListReporter
10
- def create_reporter(options)
10
+ def default_reporter(options)
11
11
  Licensed::Reporters::ListReporter.new
12
12
  end
13
13
 
14
14
  protected
15
15
 
16
+ # Run the command for all enumerated dependencies found in a dependency source,
17
+ # recording results in a report.
18
+ # Enumerating dependencies in the source is skipped if a :sources option
19
+ # is provided and the evaluated `source.class.type` is not in the :sources values
20
+ #
21
+ # app - The application configuration for the source
22
+ # source - A dependency source enumerator
23
+ #
24
+ # Returns whether the command succeeded for the dependency source enumerator
25
+ def run_source(app, source)
26
+ super do |report|
27
+ next if Array(options[:sources]).empty?
28
+ next if options[:sources].include?(source.class.type)
29
+
30
+ report.warnings << "skipped source"
31
+ :skip
32
+ end
33
+ end
34
+
16
35
  # Listing dependencies requires no extra work.
17
36
  #
18
37
  # app - The application configuration for the dependency
@@ -2,17 +2,36 @@
2
2
  module Licensed
3
3
  module Commands
4
4
  class Notices < Command
5
- # Create a reporter to use during a command run
5
+ # Returns the default reporter to use during the command run
6
6
  #
7
7
  # options - The options the command was run with
8
8
  #
9
- # Raises a Licensed::Reporters::CacheReporter
10
- def create_reporter(options)
9
+ # Returns a Licensed::Reporters::CacheReporter
10
+ def default_reporter(options)
11
11
  Licensed::Reporters::NoticesReporter.new
12
12
  end
13
13
 
14
14
  protected
15
15
 
16
+ # Run the command for all enumerated dependencies found in a dependency source,
17
+ # recording results in a report.
18
+ # Enumerating dependencies in the source is skipped if a :sources option
19
+ # is provided and the evaluated `source.class.type` is not in the :sources values
20
+ #
21
+ # app - The application configuration for the source
22
+ # source - A dependency source enumerator
23
+ #
24
+ # Returns whether the command succeeded for the dependency source enumerator
25
+ def run_source(app, source)
26
+ super do |report|
27
+ next if Array(options[:sources]).empty?
28
+ next if options[:sources].include?(source.class.type)
29
+
30
+ report.warnings << "skipped source"
31
+ :skip
32
+ end
33
+ end
34
+
16
35
  # Load stored dependency record data to add to the notices report.
17
36
  #
18
37
  # app - The application configuration for the dependency
@@ -25,7 +44,7 @@ module Licensed
25
44
  filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}")
26
45
  report["cached_record"] = Licensed::DependencyRecord.read(filename)
27
46
  if !report["cached_record"]
28
- report["warning"] = "expected cached record not found at #{filename}"
47
+ report.warnings << "expected cached record not found at #{filename}"
29
48
  end
30
49
 
31
50
  true
@@ -4,17 +4,36 @@ require "yaml"
4
4
  module Licensed
5
5
  module Commands
6
6
  class Status < Command
7
- # Create a reporter to use during a command run
7
+ # Returns the default reporter to use during the command run
8
8
  #
9
9
  # options - The options the command was run with
10
10
  #
11
11
  # Returns a Licensed::Reporters::StatusReporter
12
- def create_reporter(options)
12
+ def default_reporter(options)
13
13
  Licensed::Reporters::StatusReporter.new
14
14
  end
15
15
 
16
16
  protected
17
17
 
18
+ # Run the command for all enumerated dependencies found in a dependency source,
19
+ # recording results in a report.
20
+ # Enumerating dependencies in the source is skipped if a :sources option
21
+ # is provided and the evaluated `source.class.type` is not in the :sources values
22
+ #
23
+ # app - The application configuration for the source
24
+ # source - A dependency source enumerator
25
+ #
26
+ # Returns whether the command succeeded for the dependency source enumerator
27
+ def run_source(app, source)
28
+ super do |report|
29
+ next if Array(options[:sources]).empty?
30
+ next if options[:sources].include?(source.class.type)
31
+
32
+ report.warnings << "skipped source"
33
+ :skip
34
+ end
35
+ end
36
+
18
37
  # Verifies that a cached record exists, is up to date and
19
38
  # has license data that complies with the licensed configuration.
20
39
  #
@@ -5,6 +5,8 @@ require "licensee"
5
5
 
6
6
  module Licensed
7
7
  class DependencyRecord
8
+ class Error < StandardError; end
9
+
8
10
  class License
9
11
  attr_reader :text, :sources
10
12
  def initialize(content)
@@ -46,6 +48,8 @@ module Licensed
46
48
  notices: data.delete("notices"),
47
49
  metadata: data
48
50
  )
51
+ rescue Psych::SyntaxError => e
52
+ raise Licensed::DependencyRecord::Error.new(e.message)
49
53
  end
50
54
 
51
55
  def_delegators :@metadata, :[], :[]=
@@ -28,6 +28,22 @@ module Licensed
28
28
  shell.info " #{source.class.type}"
29
29
  result = yield report
30
30
 
31
+ warning_reports = report.all_reports.select { |r| r.warnings.any? }.to_a
32
+ if warning_reports.any?
33
+ shell.newline
34
+ shell.warn " * Warnings:"
35
+ warning_reports.each do |r|
36
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
37
+
38
+ shell.warn " * #{r.name}"
39
+ shell.warn " #{display_metadata}" unless display_metadata.empty?
40
+ r.warnings.each do |warning|
41
+ shell.warn " - #{warning}"
42
+ end
43
+ shell.newline
44
+ end
45
+ end
46
+
31
47
  errored_reports = report.all_reports.select { |r| r.errors.any? }.to_a
32
48
  if errored_reports.any?
33
49
  shell.newline
@@ -33,6 +33,26 @@ module Licensed
33
33
  end
34
34
  end
35
35
 
36
+
37
+ # Reports on a dependency source enumerator in a notices command run.
38
+ # Shows warnings encountered during the run.
39
+ #
40
+ # source - A dependency source enumerator
41
+ #
42
+ # Returns the result of the yielded method
43
+ # Note - must be called from inside the `report_run` scope
44
+ def report_source(source)
45
+ super do |report|
46
+ result = yield report
47
+
48
+ report.warnings.each do |warning|
49
+ shell.warn "* #{report.name}: #{warning}"
50
+ end
51
+
52
+ result
53
+ end
54
+ end
55
+
36
56
  # Reports on a dependency in a notices command run.
37
57
  #
38
58
  # dependency - An application dependency
@@ -42,7 +62,9 @@ module Licensed
42
62
  def report_dependency(dependency)
43
63
  super do |report|
44
64
  result = yield report
45
- shell.warn "* #{report["warning"]}" if report["warning"]
65
+ report.warnings.each do |warning|
66
+ shell.warn "* #{report.name}: #{warning}"
67
+ end
46
68
  result
47
69
  end
48
70
  end
@@ -55,7 +77,16 @@ module Licensed
55
77
  return unless cached_record
56
78
 
57
79
  texts = cached_record.licenses.map(&:text)
58
- texts.concat(cached_record.notices)
80
+ cached_record.notices.each do |notice|
81
+ case notice
82
+ when Hash
83
+ texts << notice["text"]
84
+ when String
85
+ texts << notice
86
+ else
87
+ shell.warn "* unable to parse notices for #{report.target.name}"
88
+ end
89
+ end
59
90
 
60
91
  <<~NOTICE
61
92
  #{cached_record["name"]}@#{cached_record["version"]}
@@ -15,6 +15,23 @@ module Licensed
15
15
  result = yield report
16
16
 
17
17
  all_reports = report.all_reports
18
+
19
+ warning_reports = all_reports.select { |r| r.warnings.any? }.to_a
20
+ if warning_reports.any?
21
+ shell.newline
22
+ shell.warn "Warnings:"
23
+ warning_reports.each do |r|
24
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
25
+
26
+ shell.warn "* #{r.name}"
27
+ shell.warn " #{display_metadata}" unless display_metadata.empty?
28
+ r.warnings.each do |warning|
29
+ shell.warn " - #{warning}"
30
+ end
31
+ shell.newline
32
+ end
33
+ end
34
+
18
35
  errored_reports = all_reports.select { |r| r.errors.any? }.to_a
19
36
 
20
37
  dependency_count = all_reports.select { |r| r.target.is_a?(Licensed::Dependency) }.size
@@ -74,7 +74,7 @@ module Licensed
74
74
  end
75
75
  end
76
76
 
77
- GEMFILES = %w{Gemfile gems.rb}.freeze
77
+ GEMFILES = { "Gemfile" => "Gemfile.lock", "gems.rb" => "gems.locked" }
78
78
  DEFAULT_WITHOUT_GROUPS = %i{development test}
79
79
 
80
80
  def enabled?
@@ -272,14 +272,15 @@ module Licensed
272
272
 
273
273
  # Returns the path to the Bundler Gemfile
274
274
  def gemfile_path
275
- @gemfile_path ||= GEMFILES.map { |g| config.pwd.join g }
275
+ @gemfile_path ||= GEMFILES.keys
276
+ .map { |g| config.pwd.join g }
276
277
  .find { |f| f.exist? }
277
278
  end
278
279
 
279
280
  # Returns the path to the Bundler Gemfile.lock
280
281
  def lockfile_path
281
282
  return unless gemfile_path
282
- @lockfile_path ||= gemfile_path.dirname.join("#{gemfile_path.basename}.lock")
283
+ @lockfile_path ||= gemfile_path.dirname.join(GEMFILES[gemfile_path.basename.to_s])
283
284
  end
284
285
 
285
286
  # Returns the configured bundler executable to use, or "bundle" by default.
@@ -30,7 +30,7 @@ module Licensed
30
30
  end
31
31
 
32
32
  def packages
33
- root_dependencies = JSON.parse(package_metadata_command)["dependencies"]
33
+ root_dependencies = package_metadata["dependencies"]
34
34
  recursive_dependencies(root_dependencies).each_with_object({}) do |(name, results), hsh|
35
35
  results.uniq! { |package| package["version"] }
36
36
  if results.size == 1
@@ -56,6 +56,18 @@ module Licensed
56
56
  result
57
57
  end
58
58
 
59
+ # Returns parsed package metadata returned from `npm list`
60
+ def package_metadata
61
+ return @package_metadata if defined?(@package_metadata)
62
+
63
+ @package_metadata = begin
64
+ JSON.parse(package_metadata_command)
65
+ rescue JSON::ParserError => e
66
+ raise Licensed::Sources::Source::Error,
67
+ "Licensed was unable to parse the output from 'npm list'. Please run 'npm list --json --long' and check for errors. Error: #{e.message}"
68
+ end
69
+ end
70
+
59
71
  # Returns the output from running `npm list` to get package metadata
60
72
  def package_metadata_command
61
73
  args = %w(--json --long)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "2.11.0".freeze
3
+ VERSION = "2.13.0".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
@@ -38,5 +38,4 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "rubocop", "~> 0.49", "< 0.67"
39
39
  spec.add_development_dependency "rubocop-github", "~> 0.6"
40
40
  spec.add_development_dependency "byebug", "~> 10.0.0"
41
- spec.add_development_dependency "spy", "~> 1.0.0"
42
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: licensed
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-02 00:00:00.000000000 Z
11
+ date: 2020-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee
@@ -218,20 +218,6 @@ dependencies:
218
218
  - - "~>"
219
219
  - !ruby/object:Gem::Version
220
220
  version: 10.0.0
221
- - !ruby/object:Gem::Dependency
222
- name: spy
223
- requirement: !ruby/object:Gem::Requirement
224
- requirements:
225
- - - "~>"
226
- - !ruby/object:Gem::Version
227
- version: 1.0.0
228
- type: :development
229
- prerelease: false
230
- version_requirements: !ruby/object:Gem::Requirement
231
- requirements:
232
- - - "~>"
233
- - !ruby/object:Gem::Version
234
- version: 1.0.0
235
221
  description: Licensed automates extracting and validating the licenses of dependencies.
236
222
  email:
237
223
  - opensource+licensed@github.com