licensed 2.10.0 → 2.12.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b47685dba77cc47406dfa9aa2dd805c5f4a1746ea547a5b34c39a6d2ec47dcf
4
- data.tar.gz: 0eef1add309449ee2f00a33831d780cf6250990bb74be08077cf786ab28996a2
3
+ metadata.gz: 42da8bbc3e526abe154311e85c5dcb1ffaeba7a631e3b6eab6dbb976a94d9c4d
4
+ data.tar.gz: b0884fb5ae8a8c332c8ea8684075a57e3efe86c6026656279eb2ffe0ae50105a
5
5
  SHA512:
6
- metadata.gz: e01ca0150f1690ade72d0c95743d435af9796269d6b3a51496d39b5e98c186dc0cf78dd824f565c7070dc75e8a85e5af0aad21c8382b92b1578bd09edbe89dd3
7
- data.tar.gz: 0d00ed4c4b0596f96cb2ec77972fe36352bc17a84ee7043b5c3d002db9d9b2f15c9ddf87a2b67ebf36b99eb8dc8b02b4a917e68f9d83d2d42457bb26ee3a5314
6
+ metadata.gz: e5d14b32dffb12a412090348429a116f9732bb6413bc35fb677dbf248e8af415ca531d7980bafeaa5a81ed2f083e798821cd21be7fd8eed1037a6659f24d4693
7
+ data.tar.gz: 411785733af02c33cc0b239980558f79389b8bfdc144bf862530fde111dc3ad0c8fd64040b9fdecba022ae93158287b0f45e26a10719567dda3022024a60728b
@@ -93,7 +93,7 @@ jobs:
93
93
  steps:
94
94
  - uses: actions/checkout@v2
95
95
  - name: Setup php
96
- uses: nanasess/setup-php@v1.0.2
96
+ uses: nanasess/setup-php@v3.0.4
97
97
  with:
98
98
  php-version: ${{ matrix.php }}
99
99
  - name: Set up Ruby
data/.gitignore CHANGED
@@ -45,6 +45,8 @@ test/fixtures/mix/mix.lock
45
45
  test/fixtures/yarn/*
46
46
  !test/fixtures/yarn/package.json
47
47
 
48
+ test/fixtures/nuget/obj/*
49
+
48
50
  vendor/licenses
49
51
  .licenses
50
52
  *.gem
@@ -6,6 +6,44 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.12.2
10
+ 2020-07-07
11
+
12
+ ### Changed
13
+ - Cleaned up ruby 2.7 warnings (:tada: @jurre https://github.com/github/licensed/pull/292)
14
+ - Cleaned up additional warnings in tests (https://github.com/github/licensed/pull/293)
15
+
16
+ ## 2.12.1
17
+ 2020-06-30
18
+
19
+ ### Fixed
20
+ - `licensed` no longer exits an error code when using the `--sources` CLI argument(https://github.com/github/licensed/pull/290)
21
+
22
+ ## 2.12.0
23
+ 2020-06-19
24
+
25
+ ### Added
26
+ - `--sources` argument for cache, list, status and notices commands to filter running sources (https://github.com/github/licensed/pull/287)
27
+
28
+ ### Fixed
29
+ - `cache` command will not remove files outside of enabled source cache paths (https://github.com/github/licensed/pull/287)
30
+
31
+ ## 2.11.1
32
+ 2020-06-09
33
+
34
+ ### Fixed
35
+ - `notices` command properly reads cached dependency notices contents (https://github.com/github/licensed/pull/283)
36
+
37
+ ## 2.11.0
38
+ 2020-06-02
39
+
40
+ ### Added
41
+ - `notices` command to create a `NOTICE` file for each configured app (https://github.com/github/licensed/pull/277)
42
+
43
+ ### Fixed
44
+ - NuGet source no longer crashes on a non-existent dependency path (https://github.com/github/licensed/pull/280)
45
+ - Go source no longer crashes on a non-existent dependency package path (https://github.com/github/licensed/pull/274)
46
+
9
47
  ## 2.10.0
10
48
  2020-05-15
11
49
 
@@ -13,7 +51,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
13
51
  - NPM source ignores missing peer dependencies (https://github.com/github/licensed/pull/267)
14
52
 
15
53
  ### Added
16
- - Nuget source (:tada: @zarenner https://github.com/github/licensed/pull/261)
54
+ - NuGet source (:tada: @zarenner https://github.com/github/licensed/pull/261)
17
55
  - Multiple apps can share a single cache location (https://github.com/github/licensed/pull/263)
18
56
 
19
57
  ## 2.9.2
@@ -302,4 +340,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
302
340
 
303
341
  Initial release :tada:
304
342
 
305
- [Unreleased]: https://github.com/github/licensed/compare/2.10.0...HEAD
343
+ [Unreleased]: https://github.com/github/licensed/compare/2.12.2...HEAD
data/README.md CHANGED
@@ -24,13 +24,13 @@ See the [migration documentation](./docs/migrating_to_newer_versions.md) for mor
24
24
  ### Dependencies
25
25
 
26
26
  Licensed uses the `libgit2` bindings for Ruby provided by `rugged`. `rugged` requires `cmake` and `pkg-config` which you may need to install before you can install Licensed.
27
-
27
+
28
28
  > Ubuntu
29
-
29
+
30
30
  sudo apt-get install cmake pkg-config
31
-
31
+
32
32
  > OS X
33
-
33
+
34
34
  brew install cmake pkg-config
35
35
 
36
36
  ### With a Gemfile
@@ -64,8 +64,10 @@ For system wide usage, install licensed to a location on `$PATH`, e.g. `/usr/loc
64
64
 
65
65
  - `licensed list`: Output enumerated dependencies only.
66
66
  - `licensed cache`: Cache licenses and metadata.
67
- - `licensed status`: Check status of dependencies' cached licenses. For example:
67
+ - `licensed status`: Check status of dependencies' cached licenses.
68
+ - `licensed notices`: Write a `NOTICE` file for each application configuration.
68
69
  - `licensed version`: Show current installed version of Licensed. Aliases: `-v|--version`
70
+ - `licensed env`: Output environment information from the licensed configuration.
69
71
 
70
72
  See the [commands documentation](./docs/commands.md) for additional documentation, or run `licensed -h` to see all of the current available commands.
71
73
 
@@ -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
@@ -31,6 +37,14 @@ A dependency will fail the status checks if:
31
37
  5. The cached record is flagged for re-review.
32
38
  - This occurs when the record's license text has changed since the record was reviewed.
33
39
 
40
+ ## `notices`
41
+
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`.
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
+
46
+ The `NOTICE` file contents are retrieved from cached records, with the assumption that cached records have already been reviewed in a compliance workflow.
47
+
34
48
  ## `env`
35
49
 
36
50
  Prints the runtime environment used by licensed after loading a configuration file. By default the output is in YAML format, but can be output in JSON using the `--json` flag.
@@ -10,22 +10,38 @@ 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"
18
21
  method_option :config, aliases: "-c", type: :string,
19
22
  desc: "Path to licensed configuration file"
23
+ method_option :sources, aliases: "-s", type: :array,
24
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
20
25
  def status
21
- run Licensed::Commands::Status.new(config: config)
26
+ run Licensed::Commands::Status.new(config: config), sources: options[:sources]
22
27
  end
23
28
 
24
29
  desc "list", "List dependencies"
25
30
  method_option :config, aliases: "-c", type: :string,
26
31
  desc: "Path to licensed configuration file"
32
+ method_option :sources, aliases: "-s", type: :array,
33
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
27
34
  def list
28
- run Licensed::Commands::List.new(config: config)
35
+ run Licensed::Commands::List.new(config: config), sources: options[:sources]
36
+ end
37
+
38
+ desc "notices", "Generate a NOTICE file from cached records"
39
+ method_option :config, aliases: "-c", type: :string,
40
+ desc: "Path to licensed configuration file"
41
+ method_option :sources, aliases: "-s", type: :array,
42
+ desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
43
+ def notices
44
+ run Licensed::Commands::Notices.new(config: config), sources: options[:sources]
29
45
  end
30
46
 
31
47
  map "-v" => :version
@@ -80,7 +96,7 @@ module Licensed
80
96
  end
81
97
 
82
98
  def run(command, **args)
83
- exit command.run(args)
99
+ exit command.run(**args)
84
100
  end
85
101
  end
86
102
  end
@@ -6,5 +6,6 @@ module Licensed
6
6
  require "licensed/commands/status"
7
7
  require "licensed/commands/list"
8
8
  require "licensed/commands/environment"
9
+ require "licensed/commands/notices"
9
10
  end
10
11
  end
@@ -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) }
@@ -57,7 +59,9 @@ module Licensed
57
59
  Dir.chdir app.source_path do
58
60
  begin
59
61
  # allow additional report data to be given by commands
60
- yield report if block_given?
62
+ if block_given?
63
+ next true if (yield report) == :skip
64
+ end
61
65
 
62
66
  app.sources.select(&:enabled?)
63
67
  .sort_by { |source| source.class.type }
@@ -81,7 +85,9 @@ module Licensed
81
85
  reporter.report_source(source) do |report|
82
86
  begin
83
87
  # allow additional report data to be given by commands
84
- yield report if block_given?
88
+ if block_given?
89
+ next true if (yield report) == :skip
90
+ end
85
91
 
86
92
  source.dependencies.sort_by { |dependency| dependency.name }
87
93
  .map { |dependency| run_dependency(app, source, dependency) }
@@ -114,7 +120,9 @@ module Licensed
114
120
 
115
121
  begin
116
122
  # allow additional report data to be given by commands
117
- yield report if block_given?
123
+ if block_given?
124
+ next true if (yield report) == :skip
125
+ end
118
126
 
119
127
  evaluate_dependency(app, source, dependency, report)
120
128
  rescue Licensed::Shell::Error => err
@@ -13,6 +13,25 @@ module Licensed
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
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ module Licensed
3
+ module Commands
4
+ class Notices < Command
5
+ # Create a reporter to use during a command run
6
+ #
7
+ # options - The options the command was run with
8
+ #
9
+ # Raises a Licensed::Reporters::CacheReporter
10
+ def create_reporter(options)
11
+ Licensed::Reporters::NoticesReporter.new
12
+ end
13
+
14
+ protected
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
+
35
+ # Load stored dependency record data to add to the notices report.
36
+ #
37
+ # app - The application configuration for the dependency
38
+ # source - The dependency source enumerator for the dependency
39
+ # dependency - An application dependency
40
+ # report - A report hash for the command to provide extra data for the report output.
41
+ #
42
+ # Returns true.
43
+ def evaluate_dependency(app, source, dependency, report)
44
+ filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}")
45
+ report["cached_record"] = Licensed::DependencyRecord.read(filename)
46
+ if !report["cached_record"]
47
+ report.warnings << "expected cached record not found at #{filename}"
48
+ end
49
+
50
+ true
51
+ end
52
+ end
53
+ end
54
+ end
@@ -15,6 +15,25 @@ module Licensed
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
  #
@@ -74,7 +74,7 @@ module Licensed
74
74
  def license_contents
75
75
  files = matched_files.reject { |f| f == package_file }
76
76
  .group_by(&:content)
77
- .map { |content, files| { "sources" => license_content_sources(files), "text" => content } }
77
+ .map { |content, sources| { "sources" => license_content_sources(sources), "text" => content } }
78
78
 
79
79
  files << generated_license_contents if files.empty?
80
80
  files.compact
@@ -7,5 +7,6 @@ module Licensed
7
7
  require "licensed/reporters/list_reporter"
8
8
  require "licensed/reporters/json_reporter"
9
9
  require "licensed/reporters/yaml_reporter"
10
+ require "licensed/reporters/notices_reporter"
10
11
  end
11
12
  end
@@ -27,32 +27,32 @@ module Licensed
27
27
  shell.info " #{source.class.type}"
28
28
  result = yield report
29
29
 
30
- warning_reports = report.all_reports.select { |report| report.warnings.any? }.to_a
30
+ warning_reports = report.all_reports.select { |r| r.warnings.any? }.to_a
31
31
  if warning_reports.any?
32
32
  shell.newline
33
33
  shell.warn " * Warnings:"
34
- warning_reports.each do |report|
35
- display_metadata = report.map { |k, v| "#{k}: #{v}" }.join(", ")
34
+ warning_reports.each do |r|
35
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
36
36
 
37
- shell.warn " * #{report.name}"
37
+ shell.warn " * #{r.name}"
38
38
  shell.warn " #{display_metadata}" unless display_metadata.empty?
39
- report.warnings.each do |warning|
39
+ r.warnings.each do |warning|
40
40
  shell.warn " - #{warning}"
41
41
  end
42
42
  shell.newline
43
43
  end
44
44
  end
45
45
 
46
- errored_reports = report.all_reports.select { |report| report.errors.any? }.to_a
46
+ errored_reports = report.all_reports.select { |r| r.errors.any? }.to_a
47
47
  if errored_reports.any?
48
48
  shell.newline
49
49
  shell.error " * Errors:"
50
- errored_reports.each do |report|
51
- display_metadata = report.map { |k, v| "#{k}: #{v}" }.join(", ")
50
+ errored_reports.each do |r|
51
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
52
52
 
53
- shell.error " * #{report.name}"
53
+ shell.error " * #{r.name}"
54
54
  shell.error " #{display_metadata}" unless display_metadata.empty?
55
- report.errors.each do |error|
55
+ r.errors.each do |error|
56
56
  shell.error " - #{error}"
57
57
  end
58
58
  shell.newline
@@ -28,16 +28,32 @@ module Licensed
28
28
  shell.info " #{source.class.type}"
29
29
  result = yield report
30
30
 
31
- errored_reports = report.all_reports.select { |report| report.errors.any? }.to_a
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
+
47
+ errored_reports = report.all_reports.select { |r| r.errors.any? }.to_a
32
48
  if errored_reports.any?
33
49
  shell.newline
34
50
  shell.error " * Errors:"
35
- errored_reports.each do |report|
36
- display_metadata = report.map { |k, v| "#{k}: #{v}" }.join(", ")
51
+ errored_reports.each do |r|
52
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
37
53
 
38
- shell.error " * #{report.name}"
54
+ shell.error " * #{r.name}"
39
55
  shell.error " #{display_metadata}" unless display_metadata.empty?
40
- report.errors.each do |error|
56
+ r.errors.each do |error|
41
57
  shell.error " - #{error}"
42
58
  end
43
59
  shell.newline
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Licensed
4
+ module Reporters
5
+ class NoticesReporter < Reporter
6
+ TEXT_SEPARATOR = "\n\n#{("-" * 5)}\n\n".freeze
7
+ LICENSE_SEPARATOR = "\n#{("*" * 5)}\n".freeze
8
+
9
+ # Reports on an application configuration in a notices command run
10
+ #
11
+ # app - An application configuration
12
+ #
13
+ # Returns the result of the yielded method
14
+ # Note - must be called from inside the `report_run` scope
15
+ def report_app(app)
16
+ super do |report|
17
+ filename = app["shared_cache"] ? "NOTICE.#{app["name"]}" : "NOTICE"
18
+ path = app.cache_path.join(filename)
19
+ shell.info "Writing notices for #{app["name"]} to #{path}"
20
+
21
+ result = yield report
22
+
23
+ File.open(path, "w") do |file|
24
+ file << "THIRD PARTY NOTICES\n"
25
+ file << LICENSE_SEPARATOR
26
+ file << report.all_reports
27
+ .map { |r| notices(r) }
28
+ .compact
29
+ .join(LICENSE_SEPARATOR)
30
+ end
31
+
32
+ result
33
+ end
34
+ end
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
+
56
+ # Reports on a dependency in a notices command run.
57
+ #
58
+ # dependency - An application dependency
59
+ #
60
+ # Returns the result of the yielded method
61
+ # Note - must be called from inside the `report_run` scope
62
+ def report_dependency(dependency)
63
+ super do |report|
64
+ result = yield report
65
+ report.warnings.each do |warning|
66
+ shell.warn "* #{report.name}: #{warning}"
67
+ end
68
+ result
69
+ end
70
+ end
71
+
72
+ # Returns notices information for a dependency report
73
+ def notices(report)
74
+ return unless report.target.is_a?(Licensed::Dependency)
75
+
76
+ cached_record = report["cached_record"]
77
+ return unless cached_record
78
+
79
+ texts = cached_record.licenses.map(&:text)
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
90
+
91
+ <<~NOTICE
92
+ #{cached_record["name"]}@#{cached_record["version"]}
93
+
94
+ #{texts.map(&:strip).reject(&:empty?).compact.join(TEXT_SEPARATOR)}
95
+ NOTICE
96
+ end
97
+ end
98
+ end
99
+ end
@@ -15,20 +15,37 @@ module Licensed
15
15
  result = yield report
16
16
 
17
17
  all_reports = report.all_reports
18
- errored_reports = all_reports.select { |report| report.errors.any? }.to_a
19
18
 
20
- dependency_count = all_reports.select { |report| report.target.is_a?(Licensed::Dependency) }.size
21
- error_count = errored_reports.sum { |report| report.errors.size }
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
+
35
+ errored_reports = all_reports.select { |r| r.errors.any? }.to_a
36
+
37
+ dependency_count = all_reports.select { |r| r.target.is_a?(Licensed::Dependency) }.size
38
+ error_count = errored_reports.sum { |r| r.errors.size }
22
39
 
23
40
  if error_count > 0
24
41
  shell.newline
25
42
  shell.error "Errors:"
26
- errored_reports.each do |report|
27
- display_metadata = report.map { |k, v| "#{k}: #{v}" }.join(", ")
43
+ errored_reports.each do |r|
44
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
28
45
 
29
- shell.error "* #{report.name}"
46
+ shell.error "* #{r.name}"
30
47
  shell.error " #{display_metadata}" unless display_metadata.empty?
31
- report.errors.each do |error|
48
+ r.errors.each do |error|
32
49
  shell.error " - #{error}"
33
50
  end
34
51
  shell.newline
@@ -111,11 +111,11 @@ module Licensed
111
111
  info = package_info_command(id).strip
112
112
  return missing_package(id) if info.empty?
113
113
 
114
- info.lines.each_with_object({}) do |line, info|
114
+ info.lines.each_with_object({}) do |line, hsh|
115
115
  key, value = line.split(":", 2).map(&:strip)
116
116
  next unless key && value
117
117
 
118
- info[key] = value
118
+ hsh[key] = value
119
119
  end
120
120
  end
121
121
 
@@ -120,7 +120,7 @@ module Licensed
120
120
  return go_mod["Version"] if go_mod
121
121
 
122
122
  package_directory = package["Dir"]
123
- return unless package_directory
123
+ return unless package_directory && File.exist?(package_directory)
124
124
 
125
125
  # find most recent git SHA for a package, or nil if SHA is
126
126
  # not available
@@ -17,10 +17,13 @@ module Licensed
17
17
  PROJECT_URL_REGEX = /<projectUrl>\s*(.*)\s*<\/projectUrl>/ix.freeze
18
18
  PROJECT_DESC_REGEX = /<description>\s*(.*)\s*<\/description>/ix.freeze
19
19
 
20
- def initialize(name:, version:, path:, search_root: nil, metadata: {}, errors: [])
21
- super(name: name, version: version, path: path, search_root: search_root, metadata: metadata, errors: errors)
22
- @metadata["homepage"] = project_url if project_url
23
- @metadata["summary"] = description if description
20
+ # Returns the metadata that represents this dependency. This metadata
21
+ # is written to YAML in the dependencys cached text file
22
+ def license_metadata
23
+ super.tap do |record_metadata|
24
+ record_metadata["homepage"] = project_url if project_url
25
+ record_metadata["summary"] = description if description
26
+ end
24
27
  end
25
28
 
26
29
  def nuspec_path
@@ -29,14 +32,17 @@ module Licensed
29
32
  end
30
33
 
31
34
  def nuspec_contents
32
- return unless nuspec_path
33
- @nuspec_contents ||= File.read(nuspec_path)
35
+ return @nuspec_contents if defined?(@nuspec_contents)
36
+ @nuspec_contents = begin
37
+ return unless nuspec_path && File.exist?(nuspec_path)
38
+ File.read(nuspec_path)
39
+ end
34
40
  end
35
41
 
36
42
  def project_url
37
43
  return @project_url if defined?(@project_url)
38
- return unless nuspec_contents
39
44
  @project_url = begin
45
+ return unless nuspec_contents
40
46
  match = nuspec_contents.match PROJECT_URL_REGEX
41
47
  match[1] if match && match[1]
42
48
  end
@@ -44,8 +50,8 @@ module Licensed
44
50
 
45
51
  def description
46
52
  return @description if defined?(@description)
47
- return unless nuspec_contents
48
53
  @description = begin
54
+ return unless nuspec_contents
49
55
  match = nuspec_contents.match PROJECT_DESC_REGEX
50
56
  match[1] if match && match[1]
51
57
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "2.10.0".freeze
3
+ VERSION = "2.12.2".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
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.10.0
4
+ version: 2.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-15 00:00:00.000000000 Z
11
+ date: 2020-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee
@@ -284,6 +284,7 @@ files:
284
284
  - lib/licensed/commands/command.rb
285
285
  - lib/licensed/commands/environment.rb
286
286
  - lib/licensed/commands/list.rb
287
+ - lib/licensed/commands/notices.rb
287
288
  - lib/licensed/commands/status.rb
288
289
  - lib/licensed/configuration.rb
289
290
  - lib/licensed/dependency.rb
@@ -295,6 +296,7 @@ files:
295
296
  - lib/licensed/reporters/cache_reporter.rb
296
297
  - lib/licensed/reporters/json_reporter.rb
297
298
  - lib/licensed/reporters/list_reporter.rb
299
+ - lib/licensed/reporters/notices_reporter.rb
298
300
  - lib/licensed/reporters/reporter.rb
299
301
  - lib/licensed/reporters/status_reporter.rb
300
302
  - lib/licensed/reporters/yaml_reporter.rb