licensed 2.4.0 → 2.5.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
  SHA1:
3
- metadata.gz: 4578c64f9787f2894b6366165f1a1075f61ac7eb
4
- data.tar.gz: 34ffddfaa1572948bce8bc116a5cfd093c685a13
3
+ metadata.gz: 45476f98c8dd054a36758218f6337826e90b1112
4
+ data.tar.gz: e040ac55ae8dbd3b7dd498318b8046a271c58832
5
5
  SHA512:
6
- metadata.gz: 0c9861f9d076050e389843122baeb96501f9a53e5252309576512e102fdef4f1dc7196593c66254e30a793c734a0127b53942215366a78e6f7444e04bffe9e27
7
- data.tar.gz: 51880d49fca93099ee44997b2878c29d7ed25bc88d221439fcf73039a9728ee6079d0843fd90a615ffb21f6871ce9dadd310765c3a98799e13e81138630bf7fd
6
+ metadata.gz: 6773ae7dc4f41afd8f0597c11e3ea4bda59c10de44654c9fd9b6b91bce6f2a0b0b092ecccb95dc39ce6da5678736672d6fb3fa9b48b47bf82eb1758cecc91297
7
+ data.tar.gz: 80c82cfccb88980bc3b1b04da520e740683bb18d52cc3dcc5e60801e529f5c926d64c9df80a24dfc431e4ff2271a4fef67389b7bf4b9779edd7aeb739d015036
@@ -28,7 +28,7 @@ jobs:
28
28
 
29
29
  - uses: actions/upload-artifact@master
30
30
  with:
31
- name: licensed-${{github.event.ref}}-linux-x64.tar.gz
31
+ name: ${{github.event.ref}}-linux
32
32
  path: pkg/${{github.event.ref}}/licensed-${{github.event.ref}}-linux-x64.tar.gz
33
33
 
34
34
  package_mac:
@@ -49,28 +49,28 @@ jobs:
49
49
 
50
50
  - uses: actions/upload-artifact@master
51
51
  with:
52
- name: licensed-${{github.event.ref}}-darwin-x64.tar.gz
52
+ name: ${{github.event.ref}}-darwin
53
53
  path: pkg/${{github.event.ref}}/licensed-${{github.event.ref}}-darwin-x64.tar.gz
54
-
54
+
55
55
  build_gem:
56
56
  runs-on: ubuntu-latest
57
57
  needs: tag_filter
58
-
58
+
59
59
  steps:
60
60
  - uses: actions/checkout@master
61
61
  - name: Set up Ruby 2.6
62
62
  uses: actions/setup-ruby@v1
63
63
  with:
64
64
  version: 2.6.x
65
-
65
+
66
66
  - name: Build gem
67
67
  run: gem build *.gemspec
68
-
68
+
69
69
  - uses: actions/upload-artifact@master
70
70
  with:
71
- name: licensed-${{github.event.ref}}.gem
71
+ name: ${{github.event.ref}}-gem
72
72
  path: licensed-${{github.event.ref}}.gem
73
-
73
+
74
74
  create_release:
75
75
  runs-on: ubuntu-latest
76
76
  needs: [package_linux, package_mac, build_gem]
@@ -86,38 +86,40 @@ jobs:
86
86
  needs: [create_release]
87
87
 
88
88
  steps:
89
+ - name: Set up Ruby 2.6
90
+ uses: actions/setup-ruby@v1
91
+ with:
92
+ version: 2.6.x
93
+
89
94
  - name: Download linux package
90
95
  uses: actions/download-artifact@master
91
96
  with:
92
- name: licensed-${{github.event.ref}}-linux-x64.tar.gz
97
+ name: ${{github.event.ref}}-linux
98
+
93
99
  - name: Download macOS package
94
100
  uses: actions/download-artifact@master
95
101
  with:
96
- name: licensed-${{github.event.ref}}-darwin-x64.tar.gz
102
+ name: ${{github.event.ref}}-darwin
103
+
104
+ - name: Download gem
105
+ uses: actions/download-artifact@master
106
+ with:
107
+ name: ${{github.event.ref}}-gem
97
108
 
98
109
  - name: Publish packages to GitHub Release
99
110
  uses: Roang-zero1/github-upload-release-artifacts-action@v2.0.0
100
111
  with:
101
- args: licensed-${{github.event.ref}}-linux-x64.tar.gz licensed-${{github.event.ref}}-darwin-x64.tar.gz
112
+ args: ${{github.event.ref}}-linux ${{github.event.ref}}-darwin
102
113
  env:
103
114
  GITHUB_TOKEN: ${{secrets.API_AUTH_TOKEN}}
104
115
 
105
- - name: Download gem
106
- uses: actions/download-artifact@master
107
- with:
108
- name: licensed-${{github.event.ref}}.gem
109
-
110
- - name: Set up Ruby 2.6
111
- uses: actions/setup-ruby@v1
112
- with:
113
- version: 2.6.x
114
-
115
116
  - name: Publish gem to RubyGems
116
117
  run: |
117
118
  mkdir -p $HOME/.gem
118
119
  touch $HOME/.gem/credentials
119
120
  chmod 0600 $HOME/.gem/credentials
120
121
  printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
121
- gem push *.gem
122
+ gem push "$GEM"
122
123
  env:
123
124
  GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
125
+ GEM: ${{github.event.ref}}-gem/*.gem
@@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.5.0
10
+ 2019-09-26
11
+
12
+ ### Added
13
+ - `env` command to output application environment configuration (https://github.com/github/licensed/pull/187, https://github.com/github/licensed/pull/191)
14
+
15
+ ### Changed
16
+ - `status` command will pass if multiple allowed licenses are found (https://github.com/github/licensed/pull/188)
17
+
9
18
  ## 2.4.0
10
19
  2019-09-15
11
20
 
@@ -214,4 +223,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
214
223
 
215
224
  Initial release :tada:
216
225
 
217
- [Unreleased]: https://github.com/github/licensed/compare/2.4.0...HEAD
226
+ [Unreleased]: https://github.com/github/licensed/compare/2.5.0...HEAD
data/README.md CHANGED
@@ -8,7 +8,7 @@ Licensed is **not** a complete open source license compliance solution. Please u
8
8
 
9
9
  ## Current Status
10
10
 
11
- [![Build Status](https://travis-ci.org/github/licensed.svg?branch=master)](https://travis-ci.org/github/licensed)
11
+ ![Build status](https://github.com/github/licensed/workflows/Test/badge.svg)
12
12
 
13
13
  Licensed is in active development and currently used at GitHub. See the [open issues](https://github.com/github/licensed/issues) for a list of potential work.
14
14
 
@@ -25,8 +25,15 @@ The status command finds all dependencies and checks whether each dependency has
25
25
  A dependency will fail the status checks if:
26
26
  1. No cached record is found
27
27
  2. The cached record's version is different than the current dependency's version
28
- 3. The cached record doesn't contain any license text
28
+ 3. The cached record's `licenses` data is empty
29
29
  4. The cached record's `license` metadata doesn't match an `allowed` license from the dependency's application configuration.
30
+ - If `license: other` is specified and all of the `licenses` entries match an `allowed` license a failure will not be logged
31
+
32
+ ## `env`
33
+
34
+ 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.
35
+
36
+ The output will not be equivalent to configuration input. For example, all paths will be
30
37
 
31
38
  ## `version`
32
39
 
@@ -41,7 +48,7 @@ Licensed commands inherit and override the [`Licensed::Sources::Command`](../lib
41
48
  #### Required method overrides
42
49
  1. `Licensed::Commands::Command#evaluate_dependency`
43
50
  - Runs a command execution on an application dependency.
44
-
51
+
45
52
  The `evaluate_dependency` method should contain the specific command logic. This method has access to the application configuration, dependency source enumerator and dependency currently being evaluated as well as a reporting hash to contain information about the command execution.
46
53
 
47
54
  #### Optional method overrides
@@ -59,23 +66,14 @@ The following methods break apart the different levels of command execution. Ea
59
66
 
60
67
  As an example, `Licensed::Commands::Command#run_app` calls `Reporter#report_app` to wrap every call to `Licensed::Commands::Command#run_source`.
61
68
 
62
- ##### Overriding optional methods
69
+ ##### Specifying additional report data
63
70
 
64
- The `run` methods can be overridden to provide additional reporting data or functionality. Overriding a method should call the original method with a block for the additional logic.
71
+ The `run` methods can be overridden and pass a block to `super` to provide additional reporting data or functionality.
65
72
 
66
73
  ```ruby
67
74
  def run_app(app)
68
75
  super do |report|
69
- result = yield report
70
-
71
- # do other thing
72
- call_additional_functionality(app)
73
-
74
- # add reporting information
75
- report["result"] = result
76
-
77
- # return the result
78
- result
76
+ report["my_app_data"] = true
79
77
  end
80
78
  end
81
79
  ```
@@ -35,6 +35,15 @@ module Licensed
35
35
  puts Licensed::VERSION
36
36
  end
37
37
 
38
+ desc "env", "Output licensed environment configuration"
39
+ method_option :format, enum: ["yaml", "json"], default: "yaml",
40
+ desc: "Output format"
41
+ method_option :config, aliases: "-c", type: :string,
42
+ desc: "Path to licensed configuration file"
43
+ def env
44
+ run Licensed::Commands::Environment.new(config: config), format: options[:format]
45
+ end
46
+
38
47
  desc "migrate", "Migrate from a previous version of licensed"
39
48
  method_option :config, aliases: "-c", type: :string, required: true,
40
49
  desc: "Path to licensed configuration file"
@@ -5,5 +5,6 @@ module Licensed
5
5
  require "licensed/commands/cache"
6
6
  require "licensed/commands/status"
7
7
  require "licensed/commands/list"
8
+ require "licensed/commands/environment"
8
9
  end
9
10
  end
@@ -2,8 +2,13 @@
2
2
  module Licensed
3
3
  module Commands
4
4
  class Cache < Command
5
- def initialize(config:, reporter: Licensed::Reporters::CacheReporter.new)
6
- super(config: config, reporter: reporter)
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::CacheReporter.new
7
12
  end
8
13
 
9
14
  protected
@@ -6,9 +6,8 @@ module Licensed
6
6
  attr_reader :reporter
7
7
  attr_reader :options
8
8
 
9
- def initialize(config:, reporter:)
9
+ def initialize(config:)
10
10
  @config = config
11
- @reporter = reporter
12
11
  end
13
12
 
14
13
  # Run the command
@@ -18,19 +17,33 @@ module Licensed
18
17
  # Returns whether the command was a success
19
18
  def run(**options)
20
19
  @options = options
20
+ @reporter = create_reporter(options)
21
21
  begin
22
- result = reporter.report_run(self) do
22
+ result = reporter.report_run(self) do |report|
23
+ # allow additional report data to be given by commands
24
+ yield report if block_given?
25
+
23
26
  config.apps.sort_by { |app| app["name"] }
24
27
  .map { |app| run_app(app) }
25
28
  .all?
26
29
  end
27
30
  ensure
28
31
  @options = nil
32
+ @reporter = nil
29
33
  end
30
34
 
31
35
  result
32
36
  end
33
37
 
38
+ # Create a reporter to use during a command run
39
+ #
40
+ # options - The options the command was run with
41
+ #
42
+ # Raises an error
43
+ def create_reporter(options)
44
+ raise "`create_reporter` must be implemented by commands"
45
+ end
46
+
34
47
  protected
35
48
 
36
49
  # Run the command for all enabled sources for an application configuration,
@@ -43,6 +56,9 @@ module Licensed
43
56
  reporter.report_app(app) do |report|
44
57
  Dir.chdir app.source_path do
45
58
  begin
59
+ # allow additional report data to be given by commands
60
+ yield report if block_given?
61
+
46
62
  app.sources.select(&:enabled?)
47
63
  .sort_by { |source| source.class.type }
48
64
  .map { |source| run_source(app, source) }.all?
@@ -64,6 +80,9 @@ module Licensed
64
80
  def run_source(app, source)
65
81
  reporter.report_source(source) do |report|
66
82
  begin
83
+ # allow additional report data to be given by commands
84
+ yield report if block_given?
85
+
67
86
  source.dependencies.sort_by { |dependency| dependency.name }
68
87
  .map { |dependency| run_dependency(app, source, dependency) }
69
88
  .all?
@@ -94,6 +113,9 @@ module Licensed
94
113
  end
95
114
 
96
115
  begin
116
+ # allow additional report data to be given by commands
117
+ yield report if block_given?
118
+
97
119
  evaluate_dependency(app, source, dependency, report)
98
120
  rescue Licensed::Shell::Error => err
99
121
  report.errors << err.message
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ module Licensed
3
+ module Commands
4
+ class Environment < Command
5
+ class AppEnvironment
6
+ include Licensed::Sources::ContentVersioning
7
+
8
+ attr_reader :config
9
+ def initialize(config)
10
+ @config = config
11
+ end
12
+
13
+ def enabled_source_types
14
+ config.sources.select { |s| s.enabled? }.map { |s| s.class.type }
15
+ end
16
+
17
+ def to_h
18
+ {
19
+ "name" => config["name"],
20
+ "source_path" => config.source_path,
21
+ "cache_path" => config.cache_path,
22
+ "sources" => enabled_source_types,
23
+ "allowed" => config["allowed"],
24
+ "ignored" => config["ignored"],
25
+ "reviewed" => config["reviewed"],
26
+ "version_strategy" => self.version_strategy
27
+ }
28
+ end
29
+ end
30
+
31
+ def run(**options)
32
+ super do |report|
33
+ report["root"] = config.root
34
+ report["git_repo"] = Licensed::Git.git_repo?
35
+ end
36
+ end
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
45
+ end
46
+
47
+ protected
48
+
49
+ def run_app(app)
50
+ reporter.report_app(app) do |report|
51
+ report.merge! AppEnvironment.new(app).to_h
52
+ true
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -2,8 +2,13 @@
2
2
  module Licensed
3
3
  module Commands
4
4
  class List < Command
5
- def initialize(config:, reporter: Licensed::Reporters::ListReporter.new)
6
- super(config: config, reporter: reporter)
5
+ # Create a reporter to use during a command run
6
+ #
7
+ # options - The options the command was run with
8
+ #
9
+ # Returns a Licensed::Reporters::ListReporter
10
+ def create_reporter(options)
11
+ Licensed::Reporters::ListReporter.new
7
12
  end
8
13
 
9
14
  protected
@@ -4,8 +4,13 @@ require "yaml"
4
4
  module Licensed
5
5
  module Commands
6
6
  class Status < Command
7
- def initialize(config:, reporter: Licensed::Reporters::StatusReporter.new)
8
- super(config: config, reporter: reporter)
7
+ # Create a reporter to use during a command run
8
+ #
9
+ # options - The options the command was run with
10
+ #
11
+ # Returns a Licensed::Reporters::StatusReporter
12
+ def create_reporter(options)
13
+ Licensed::Reporters::StatusReporter.new
9
14
  end
10
15
 
11
16
  protected
@@ -30,20 +35,52 @@ module Licensed
30
35
  else
31
36
  report.errors << "cached dependency record out of date" if cached_record["version"] != dependency.version
32
37
  report.errors << "missing license text" if cached_record.licenses.empty?
33
- report.errors << "license needs review: #{cached_record["license"]}" unless allowed_or_reviewed?(app, cached_record)
38
+ report.errors << "license needs review: #{cached_record["license"]}" if license_needs_review?(app, cached_record)
34
39
  end
35
40
 
36
41
  report.errors.empty?
37
42
  end
38
43
 
39
- def allowed_or_reviewed?(app, dependency)
40
- app.allowed?(dependency) || app.reviewed?(dependency)
44
+ # Returns true if a cached record needs further review based on the
45
+ # record's license(s) and the app's configuration
46
+ def license_needs_review?(app, cached_record)
47
+ # review is not needed if the record is set as reviewed
48
+ return false if app.reviewed?(cached_record)
49
+ # review is not needed if the top level license is allowed
50
+ return false if app.allowed?(cached_record["license"])
51
+
52
+ # the remaining checks are meant to allow records marked as "other"
53
+ # that have multiple licenses, all of which are allowed
54
+
55
+ # review is needed for non-"other" licenses
56
+ return true unless cached_record["license"] == "other"
57
+
58
+ licenses = cached_record.licenses.map { |license| license_from_text(license.text) }
59
+
60
+ # review is needed when there is only one license notice
61
+ # this is a performance optimization for the single license case
62
+ return true unless licenses.length > 1
63
+
64
+ # review is needed if any license notices don't represent an allowed license
65
+ licenses.any? { |license| !app.allowed?(license) }
41
66
  end
42
67
 
43
68
  def cached_record(filename)
44
69
  return nil unless File.exist?(filename)
45
70
  DependencyRecord.read(filename)
46
71
  end
72
+
73
+ # Returns a license key based on the content from a cached records `licenses`
74
+ # entry content
75
+ def license_from_text(text)
76
+ licenses = [
77
+ Licensee::ProjectFiles::LicenseFile.new(text).license&.key,
78
+ Licensee::ProjectFiles::ReadmeFile.new(text).license&.key,
79
+ "other"
80
+ ].compact
81
+
82
+ licenses.sort_by { |license| license != "other" ? 0 : 1 }.first
83
+ end
47
84
  end
48
85
  end
49
86
  end
@@ -79,8 +79,8 @@ module Licensed
79
79
  end
80
80
 
81
81
  # Is the license of the dependency allowed?
82
- def allowed?(dependency)
83
- Array(self["allowed"]).include?(dependency["license"])
82
+ def allowed?(license)
83
+ Array(self["allowed"]).include?(license)
84
84
  end
85
85
 
86
86
  # Ignore a dependency
@@ -5,6 +5,28 @@ require "licensee"
5
5
 
6
6
  module Licensed
7
7
  class DependencyRecord
8
+ class License
9
+ attr_reader :text, :sources
10
+ def initialize(content)
11
+ @sources = []
12
+
13
+ if content.is_a?(String)
14
+ @text = content.to_s
15
+ elsif content.respond_to?(:[])
16
+ @sources.concat content["sources"].to_s.split(", ")
17
+ @text = content["text"]
18
+ end
19
+ end
20
+
21
+ def to_cache
22
+ return text if sources.empty?
23
+ {
24
+ "sources" => sources.join(", "),
25
+ "text" => text
26
+ }
27
+ end
28
+ end
29
+
8
30
  include Licensee::ContentHelper
9
31
  extend Forwardable
10
32
 
@@ -36,7 +58,7 @@ module Licensed
36
58
  # notices - a string, or array of strings, representing the content of each legal notice
37
59
  # metadata - a Hash of the metadata for the package
38
60
  def initialize(licenses: [], notices: [], metadata: {})
39
- @licenses = [licenses].flatten.compact
61
+ @licenses = [licenses].flatten.compact.map { |l| DependencyRecord::License.new(l) }
40
62
  @notices = [notices].flatten.compact
41
63
  @metadata = metadata
42
64
  end
@@ -46,7 +68,7 @@ module Licensed
46
68
  # filename - The destination file to save record contents at
47
69
  def save(filename)
48
70
  data_to_save = @metadata.merge({
49
- "licenses" => licenses,
71
+ "licenses" => licenses.map(&:to_cache),
50
72
  "notices" => notices
51
73
  })
52
74
 
@@ -58,13 +80,7 @@ module Licensed
58
80
  # `Licensee::CotentHelper`
59
81
  def content
60
82
  return if licenses.nil? || licenses.empty?
61
- licenses.map do |license|
62
- if license.is_a?(String)
63
- license
64
- elsif license.respond_to?(:[])
65
- license["text"]
66
- end
67
- end.join
83
+ licenses.map(&:text).compact.join
68
84
  end
69
85
 
70
86
  # Returns whether two records match based on their contents
@@ -5,5 +5,7 @@ module Licensed
5
5
  require "licensed/reporters/cache_reporter"
6
6
  require "licensed/reporters/status_reporter"
7
7
  require "licensed/reporters/list_reporter"
8
+ require "licensed/reporters/json_reporter"
9
+ require "licensed/reporters/yaml_reporter"
8
10
  end
9
11
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ require "json"
3
+
4
+ module Licensed
5
+ module Reporters
6
+ class JsonReporter < Reporter
7
+ def report_run(command)
8
+ super do |report|
9
+ result = yield report
10
+
11
+ report["apps"] = report.reports.map(&:to_h) if report.reports.any?
12
+ shell.info JSON.pretty_generate(report.to_h)
13
+
14
+ result
15
+ end
16
+ end
17
+
18
+ def report_app(app)
19
+ super do |report|
20
+ result = yield report
21
+ report["sources"] = report.reports.map(&:to_h) if report.reports.any?
22
+ result
23
+ end
24
+ end
25
+
26
+ def report_source(source)
27
+ super do |report|
28
+ result = yield report
29
+ report["dependencies"] = report.reports.map(&:to_h) if report.reports.any?
30
+ result
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -28,6 +28,19 @@ module Licensed
28
28
  result << self
29
29
  result.push(*reports.flat_map(&:all_reports))
30
30
  end
31
+
32
+ # Returns the data from the report as a hash
33
+ def to_h
34
+ # add name, errors and warnings if they have real data
35
+ output = {}
36
+ output["name"] = name unless name.to_s.empty?
37
+ output["errors"] = errors.dup if errors.any?
38
+ output["warnings"] = warnings.dup if warnings.any?
39
+
40
+ # merge the hash data from the report. command-specified data always
41
+ # overwrites local data
42
+ output.merge(super)
43
+ end
31
44
  end
32
45
 
33
46
  class ReportingError < StandardError; end;
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ module Licensed
3
+ module Reporters
4
+ class YamlReporter < Reporter
5
+ def report_run(command)
6
+ super do |report|
7
+ result = yield report
8
+
9
+ report["apps"] = report.reports.map(&:to_h) if report.reports.any?
10
+ shell.info sanitize(report.to_h).to_yaml
11
+
12
+ result
13
+ end
14
+ end
15
+
16
+ def report_app(app)
17
+ super do |report|
18
+ result = yield report
19
+ report["sources"] = report.reports.map(&:to_h) if report.reports.any?
20
+ result
21
+ end
22
+ end
23
+
24
+ def report_source(source)
25
+ super do |report|
26
+ result = yield report
27
+ report["dependencies"] = report.reports.map(&:to_h) if report.reports.any?
28
+ result
29
+ end
30
+ end
31
+
32
+ def sanitize(object)
33
+ case object
34
+ when String, TrueClass, FalseClass, Numeric
35
+ object
36
+ when Array
37
+ object.compact.map { |item| sanitize(item) }
38
+ when Hash
39
+ object.reject { |_, v| v.nil? }
40
+ .map { |k, v| [k.to_s, sanitize(v)] }
41
+ .to_h
42
+ else
43
+ object.to_s
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "2.4.0".freeze
3
+ VERSION = "2.5.0".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
@@ -36,4 +36,5 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency "rubocop", "~> 0.49", "< 0.67"
37
37
  spec.add_development_dependency "rubocop-github", "~> 0.6"
38
38
  spec.add_development_dependency "byebug", "~> 10.0.0"
39
+ spec.add_development_dependency "spy", "~> 1.0.0"
39
40
  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.4.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-15 00:00:00.000000000 Z
11
+ date: 2019-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee
@@ -184,6 +184,20 @@ dependencies:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
186
  version: 10.0.0
187
+ - !ruby/object:Gem::Dependency
188
+ name: spy
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: 1.0.0
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: 1.0.0
187
201
  description: Licensed automates extracting and validating the licenses of dependencies.
188
202
  email:
189
203
  - opensource+licensed@github.com
@@ -231,6 +245,7 @@ files:
231
245
  - lib/licensed/commands.rb
232
246
  - lib/licensed/commands/cache.rb
233
247
  - lib/licensed/commands/command.rb
248
+ - lib/licensed/commands/environment.rb
234
249
  - lib/licensed/commands/list.rb
235
250
  - lib/licensed/commands/status.rb
236
251
  - lib/licensed/configuration.rb
@@ -241,9 +256,11 @@ files:
241
256
  - lib/licensed/migrations/v2.rb
242
257
  - lib/licensed/reporters.rb
243
258
  - lib/licensed/reporters/cache_reporter.rb
259
+ - lib/licensed/reporters/json_reporter.rb
244
260
  - lib/licensed/reporters/list_reporter.rb
245
261
  - lib/licensed/reporters/reporter.rb
246
262
  - lib/licensed/reporters/status_reporter.rb
263
+ - lib/licensed/reporters/yaml_reporter.rb
247
264
  - lib/licensed/shell.rb
248
265
  - lib/licensed/sources.rb
249
266
  - lib/licensed/sources/bower.rb