licensed 2.10.0 → 2.11.0

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: 9cb9d80097e4329d3aa276faf53b72cac7fed2c2f4c09edc500bc627fb8d942b
4
+ data.tar.gz: f2ba113cfac5f807980f44a7d60a40dd6c946c85a351bf8161854b72d715d625
5
5
  SHA512:
6
- metadata.gz: e01ca0150f1690ade72d0c95743d435af9796269d6b3a51496d39b5e98c186dc0cf78dd824f565c7070dc75e8a85e5af0aad21c8382b92b1578bd09edbe89dd3
7
- data.tar.gz: 0d00ed4c4b0596f96cb2ec77972fe36352bc17a84ee7043b5c3d002db9d9b2f15c9ddf87a2b67ebf36b99eb8dc8b02b4a917e68f9d83d2d42457bb26ee3a5314
6
+ metadata.gz: dcdc95e2d512dbf8f9e84f76409f4d94b93ae3bdf95d17fa4b668f04e996cdcda340c5e7f09dd499c509b122e92cfc90d58838f33df24d690fd4ae1b759550b0
7
+ data.tar.gz: bba8ba26db299965d6fc7e2d783060d827e5f45cd7f1a287414f63c39298b39dfb6739beebe46d152e6619830705a8abf822a33ce01d94335fc195596a65e6cb
@@ -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,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.11.0
10
+ 2020-06-02
11
+
12
+ ### Added
13
+ - `notices` command to create a `NOTICE` file for each configured app (https://github.com/github/licensed/pull/277)
14
+
15
+ ### Fixed
16
+ - NuGet source no longer crashes on a non-existent dependency path (https://github.com/github/licensed/pull/280)
17
+ - Go source no longer crashes on a non-existent dependency package path (https://github.com/github/licensed/pull/274)
18
+
9
19
  ## 2.10.0
10
20
  2020-05-15
11
21
 
@@ -13,7 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
13
23
  - NPM source ignores missing peer dependencies (https://github.com/github/licensed/pull/267)
14
24
 
15
25
  ### Added
16
- - Nuget source (:tada: @zarenner https://github.com/github/licensed/pull/261)
26
+ - NuGet source (:tada: @zarenner https://github.com/github/licensed/pull/261)
17
27
  - Multiple apps can share a single cache location (https://github.com/github/licensed/pull/263)
18
28
 
19
29
  ## 2.9.2
@@ -302,4 +312,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
302
312
 
303
313
  Initial release :tada:
304
314
 
305
- [Unreleased]: https://github.com/github/licensed/compare/2.10.0...HEAD
315
+ [Unreleased]: https://github.com/github/licensed/compare/2.11.0...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
 
@@ -31,6 +31,12 @@ A dependency will fail the status checks if:
31
31
  5. The cached record is flagged for re-review.
32
32
  - This occurs when the record's license text has changed since the record was reviewed.
33
33
 
34
+ ## `notices`
35
+
36
+ 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
+
38
+ The `NOTICE` file contents are retrieved from cached records, with the assumption that cached records have already been reviewed in a compliance workflow.
39
+
34
40
  ## `env`
35
41
 
36
42
  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.
@@ -28,6 +28,13 @@ module Licensed
28
28
  run Licensed::Commands::List.new(config: config)
29
29
  end
30
30
 
31
+ desc "notices", "Generate a NOTICE file from cached records"
32
+ method_option :config, aliases: "-c", type: :string,
33
+ desc: "Path to licensed configuration file"
34
+ def notices
35
+ run Licensed::Commands::Notices.new(config: config)
36
+ end
37
+
31
38
  map "-v" => :version
32
39
  map "--version" => :version
33
40
  desc "version", "Show Installed Version of Licensed, [-v, --version]"
@@ -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
@@ -0,0 +1,35 @@
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
+ # Load stored dependency record data to add to the notices report.
17
+ #
18
+ # app - The application configuration for the dependency
19
+ # source - The dependency source enumerator for the dependency
20
+ # dependency - An application dependency
21
+ # report - A report hash for the command to provide extra data for the report output.
22
+ #
23
+ # Returns true.
24
+ def evaluate_dependency(app, source, dependency, report)
25
+ filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}")
26
+ report["cached_record"] = Licensed::DependencyRecord.read(filename)
27
+ if !report["cached_record"]
28
+ report["warning"] = "expected cached record not found at #{filename}"
29
+ end
30
+
31
+ true
32
+ end
33
+ end
34
+ end
35
+ end
@@ -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,16 @@ 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
+ errored_reports = report.all_reports.select { |r| r.errors.any? }.to_a
32
32
  if errored_reports.any?
33
33
  shell.newline
34
34
  shell.error " * Errors:"
35
- errored_reports.each do |report|
36
- display_metadata = report.map { |k, v| "#{k}: #{v}" }.join(", ")
35
+ errored_reports.each do |r|
36
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
37
37
 
38
- shell.error " * #{report.name}"
38
+ shell.error " * #{r.name}"
39
39
  shell.error " #{display_metadata}" unless display_metadata.empty?
40
- report.errors.each do |error|
40
+ r.errors.each do |error|
41
41
  shell.error " - #{error}"
42
42
  end
43
43
  shell.newline
@@ -0,0 +1,68 @@
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
+ # Reports on a dependency in a notices command run.
37
+ #
38
+ # dependency - An application dependency
39
+ #
40
+ # Returns the result of the yielded method
41
+ # Note - must be called from inside the `report_run` scope
42
+ def report_dependency(dependency)
43
+ super do |report|
44
+ result = yield report
45
+ shell.warn "* #{report["warning"]}" if report["warning"]
46
+ result
47
+ end
48
+ end
49
+
50
+ # Returns notices information for a dependency report
51
+ def notices(report)
52
+ return unless report.target.is_a?(Licensed::Dependency)
53
+
54
+ cached_record = report["cached_record"]
55
+ return unless cached_record
56
+
57
+ texts = cached_record.licenses.map(&:text)
58
+ texts.concat(cached_record.notices)
59
+
60
+ <<~NOTICE
61
+ #{cached_record["name"]}@#{cached_record["version"]}
62
+
63
+ #{texts.map(&:strip).reject(&:empty?).compact.join(TEXT_SEPARATOR)}
64
+ NOTICE
65
+ end
66
+ end
67
+ end
68
+ end
@@ -15,20 +15,20 @@ 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
18
+ errored_reports = all_reports.select { |r| r.errors.any? }.to_a
19
19
 
20
- dependency_count = all_reports.select { |report| report.target.is_a?(Licensed::Dependency) }.size
21
- error_count = errored_reports.sum { |report| report.errors.size }
20
+ dependency_count = all_reports.select { |r| r.target.is_a?(Licensed::Dependency) }.size
21
+ error_count = errored_reports.sum { |r| r.errors.size }
22
22
 
23
23
  if error_count > 0
24
24
  shell.newline
25
25
  shell.error "Errors:"
26
- errored_reports.each do |report|
27
- display_metadata = report.map { |k, v| "#{k}: #{v}" }.join(", ")
26
+ errored_reports.each do |r|
27
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
28
28
 
29
- shell.error "* #{report.name}"
29
+ shell.error "* #{r.name}"
30
30
  shell.error " #{display_metadata}" unless display_metadata.empty?
31
- report.errors.each do |error|
31
+ r.errors.each do |error|
32
32
  shell.error " - #{error}"
33
33
  end
34
34
  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.11.0".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.11.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-05-15 00:00:00.000000000 Z
11
+ date: 2020-06-02 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