licensed 3.1.0 → 3.2.3
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 +4 -4
- data/.github/dependabot.yml +19 -0
- data/.github/workflows/release.yml +4 -4
- data/.github/workflows/test.yml +169 -48
- data/.ruby-version +1 -1
- data/CHANGELOG.md +51 -1
- data/README.md +25 -80
- data/docker/Dockerfile.build-linux +1 -1
- data/docs/adding_a_new_source.md +11 -8
- data/docs/commands/README.md +59 -0
- data/docs/commands/cache.md +35 -0
- data/docs/commands/env.md +10 -0
- data/docs/commands/list.md +23 -0
- data/docs/commands/migrate.md +10 -0
- data/docs/commands/notices.md +12 -0
- data/docs/commands/status.md +74 -0
- data/docs/commands/version.md +3 -0
- data/docs/configuration/README.md +11 -0
- data/docs/configuration/allowed_licenses.md +17 -0
- data/docs/configuration/application_name.md +63 -0
- data/docs/configuration/application_source.md +64 -0
- data/docs/configuration/configuration_root.md +27 -0
- data/docs/configuration/configuring_multiple_apps.md +58 -0
- data/docs/configuration/dependency_source_enumerators.md +28 -0
- data/docs/configuration/ignoring_dependencies.md +19 -0
- data/docs/configuration/metadata_cache.md +106 -0
- data/docs/configuration/reviewing_dependencies.md +18 -0
- data/docs/configuration.md +9 -173
- data/lib/licensed/cli.rb +2 -2
- data/lib/licensed/commands/cache.rb +21 -20
- data/lib/licensed/commands/command.rb +108 -73
- data/lib/licensed/commands/environment.rb +12 -11
- data/lib/licensed/commands/list.rb +0 -19
- data/lib/licensed/commands/notices.rb +0 -19
- data/lib/licensed/commands/status.rb +13 -15
- data/lib/licensed/configuration.rb +77 -7
- data/lib/licensed/report.rb +44 -0
- data/lib/licensed/reporters/cache_reporter.rb +48 -64
- data/lib/licensed/reporters/json_reporter.rb +19 -21
- data/lib/licensed/reporters/list_reporter.rb +45 -58
- data/lib/licensed/reporters/notices_reporter.rb +33 -46
- data/lib/licensed/reporters/reporter.rb +37 -104
- data/lib/licensed/reporters/status_reporter.rb +58 -56
- data/lib/licensed/reporters/yaml_reporter.rb +19 -21
- data/lib/licensed/sources/bundler/definition.rb +36 -0
- data/lib/licensed/sources/bundler/missing_specification.rb +10 -7
- data/lib/licensed/sources/bundler.rb +34 -70
- data/lib/licensed/sources/dep.rb +2 -2
- data/lib/licensed/sources/go.rb +3 -3
- data/lib/licensed/sources/gradle.rb +2 -2
- data/lib/licensed/sources/helpers/content_versioning.rb +2 -1
- data/lib/licensed/sources/npm.rb +4 -3
- data/lib/licensed/sources/nuget.rb +1 -2
- data/lib/licensed/version.rb +1 -1
- data/lib/licensed.rb +1 -0
- data/licensed.gemspec +4 -4
- data/script/source-setup/go +1 -1
- metadata +45 -13
- data/docs/commands.md +0 -95
data/lib/licensed/cli.rb
CHANGED
@@ -20,12 +20,12 @@ module Licensed
|
|
20
20
|
end
|
21
21
|
|
22
22
|
desc "status", "Check status of dependencies' cached licenses"
|
23
|
-
method_option :format, enum: ["yaml", "json"],
|
24
|
-
desc: "Output format"
|
25
23
|
method_option :config, aliases: "-c", type: :string,
|
26
24
|
desc: "Path to licensed configuration file"
|
27
25
|
method_option :sources, aliases: "-s", type: :array,
|
28
26
|
desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
|
27
|
+
method_option :format, aliases: "-f", enum: ["yaml", "json"],
|
28
|
+
desc: "Output format"
|
29
29
|
def status
|
30
30
|
run Licensed::Commands::Status.new(config: config), sources: options[:sources], reporter: options[:format]
|
31
31
|
end
|
@@ -11,6 +11,8 @@ module Licensed
|
|
11
11
|
Licensed::Reporters::CacheReporter.new
|
12
12
|
end
|
13
13
|
|
14
|
+
protected
|
15
|
+
|
14
16
|
# Run the command.
|
15
17
|
# Removes any cached records that don't match a current application
|
16
18
|
# dependency.
|
@@ -18,20 +20,15 @@ module Licensed
|
|
18
20
|
# options - Options to run the command with
|
19
21
|
#
|
20
22
|
# Returns whether the command was a success
|
21
|
-
def
|
22
|
-
|
23
|
-
result = super
|
23
|
+
def run_command(report)
|
24
|
+
super do |result|
|
24
25
|
clear_stale_cached_records if result
|
25
|
-
|
26
|
-
result
|
27
|
-
ensure
|
28
|
-
cache_paths.clear
|
29
|
-
files.clear
|
30
26
|
end
|
27
|
+
ensure
|
28
|
+
cache_paths.clear
|
29
|
+
files.clear
|
31
30
|
end
|
32
31
|
|
33
|
-
protected
|
34
|
-
|
35
32
|
# Run the command for all enumerated dependencies found in a dependency source,
|
36
33
|
# recording results in a report.
|
37
34
|
# Enumerating dependencies in the source is skipped if a :sources option
|
@@ -41,17 +38,14 @@ module Licensed
|
|
41
38
|
# source - A dependency source enumerator
|
42
39
|
#
|
43
40
|
# Returns whether the command succeeded for the dependency source enumerator
|
44
|
-
def run_source(app, source)
|
45
|
-
|
46
|
-
if Array(options[:sources]).any? && !options[:sources].include?(source.class.type)
|
47
|
-
report.warnings << "skipped source"
|
48
|
-
next :skip
|
49
|
-
end
|
41
|
+
def run_source(app, source, report)
|
42
|
+
result = super
|
50
43
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
# add the full cache path to the list of cache paths
|
45
|
+
# that should be cleaned up after the command run
|
46
|
+
cache_paths << app.cache_path.join(source.class.type) unless result == :skipped
|
47
|
+
|
48
|
+
result
|
55
49
|
end
|
56
50
|
|
57
51
|
# Cache dependency record data.
|
@@ -70,6 +64,12 @@ module Licensed
|
|
70
64
|
|
71
65
|
filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}")
|
72
66
|
cached_record = Licensed::DependencyRecord.read(filename)
|
67
|
+
|
68
|
+
report["cached"] = false
|
69
|
+
report["license"] = cached_record["license"] if cached_record
|
70
|
+
report["filename"] = filename.to_s
|
71
|
+
report["version"] = dependency.version
|
72
|
+
|
73
73
|
if options[:force] || save_dependency_record?(dependency, cached_record)
|
74
74
|
if dependency.record.matches?(cached_record)
|
75
75
|
# use the cached license value if the license text wasn't updated
|
@@ -82,6 +82,7 @@ module Licensed
|
|
82
82
|
|
83
83
|
dependency.record.save(filename)
|
84
84
|
report["cached"] = true
|
85
|
+
report["license"] = dependency.record["license"]
|
85
86
|
end
|
86
87
|
|
87
88
|
if !dependency.exist?
|
@@ -18,23 +18,12 @@ module Licensed
|
|
18
18
|
def run(**options)
|
19
19
|
@options = options
|
20
20
|
@reporter = create_reporter(options)
|
21
|
-
begin
|
22
|
-
result = reporter.report_run(self) do |report|
|
23
|
-
# allow additional report data to be given by commands
|
24
|
-
if block_given?
|
25
|
-
next true if (yield report) == :skip
|
26
|
-
end
|
27
|
-
|
28
|
-
config.apps.sort_by { |app| app["name"] }
|
29
|
-
.map { |app| run_app(app) }
|
30
|
-
.all?
|
31
|
-
end
|
32
|
-
ensure
|
33
|
-
@options = nil
|
34
|
-
@reporter = nil
|
35
|
-
end
|
36
21
|
|
37
|
-
|
22
|
+
command_report = Licensed::Report.new(name: nil, target: self)
|
23
|
+
run_command(command_report)
|
24
|
+
ensure
|
25
|
+
@options = nil
|
26
|
+
@reporter = nil
|
38
27
|
end
|
39
28
|
|
40
29
|
# Creates a reporter to use during a command run
|
@@ -64,36 +53,65 @@ module Licensed
|
|
64
53
|
|
65
54
|
protected
|
66
55
|
|
56
|
+
# Run the command for all application configurations
|
57
|
+
#
|
58
|
+
# report - A Licensed::Report object for this command
|
59
|
+
#
|
60
|
+
# Returns whether the command succeeded
|
61
|
+
def run_command(report)
|
62
|
+
reporter.begin_report_command(self, report)
|
63
|
+
apps = config.apps.sort_by { |app| app["name"] }
|
64
|
+
results = apps.map do |app|
|
65
|
+
app_report = Licensed::Report.new(name: app["name"], target: app)
|
66
|
+
report.reports << app_report
|
67
|
+
run_app(app, app_report)
|
68
|
+
end
|
69
|
+
|
70
|
+
result = results.all?
|
71
|
+
|
72
|
+
yield(result) if block_given?
|
73
|
+
|
74
|
+
result
|
75
|
+
ensure
|
76
|
+
reporter.end_report_command(self, report)
|
77
|
+
end
|
78
|
+
|
67
79
|
# Run the command for all enabled sources for an application configuration,
|
68
80
|
# recording results in a report.
|
69
81
|
#
|
70
82
|
# app - An application configuration
|
83
|
+
# report - A report object for this application
|
71
84
|
#
|
72
85
|
# Returns whether the command succeeded for the application.
|
73
|
-
def run_app(app)
|
74
|
-
reporter.
|
75
|
-
# ensure the app source path exists before evaluation
|
76
|
-
if !Dir.exist?(app.source_path)
|
77
|
-
report.errors << "No such directory #{app.source_path}"
|
78
|
-
next false
|
79
|
-
end
|
86
|
+
def run_app(app, report)
|
87
|
+
reporter.begin_report_app(app, report)
|
80
88
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
89
|
+
# ensure the app source path exists before evaluation
|
90
|
+
if !Dir.exist?(app.source_path)
|
91
|
+
report.errors << "No such directory #{app.source_path}"
|
92
|
+
return false
|
93
|
+
end
|
94
|
+
|
95
|
+
Dir.chdir app.source_path do
|
96
|
+
sources = app.sources.select(&:enabled?)
|
97
|
+
.sort_by { |source| source.class.type }
|
98
|
+
results = sources.map do |source|
|
99
|
+
source_report = Licensed::Report.new(name: [report.name, source.class.type].join("."), target: source)
|
100
|
+
report.reports << source_report
|
101
|
+
run_source(app, source, source_report)
|
95
102
|
end
|
103
|
+
|
104
|
+
result = results.all?
|
105
|
+
|
106
|
+
yield(result) if block_given?
|
107
|
+
|
108
|
+
result
|
96
109
|
end
|
110
|
+
rescue Licensed::Shell::Error => err
|
111
|
+
report.errors << err.message
|
112
|
+
false
|
113
|
+
ensure
|
114
|
+
reporter.end_report_app(app, report)
|
97
115
|
end
|
98
116
|
|
99
117
|
# Run the command for all enumerated dependencies found in a dependency source,
|
@@ -101,27 +119,40 @@ module Licensed
|
|
101
119
|
#
|
102
120
|
# app - The application configuration for the source
|
103
121
|
# source - A dependency source enumerator
|
122
|
+
# report - A report object for this source
|
104
123
|
#
|
105
|
-
# Returns whether the command succeeded for the dependency source enumerator
|
106
|
-
def run_source(app, source)
|
107
|
-
reporter.
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
false
|
123
|
-
end
|
124
|
+
# Returns whether the command succeeded, failed, or was skipped for the dependency source enumerator
|
125
|
+
def run_source(app, source, report)
|
126
|
+
reporter.begin_report_source(source, report)
|
127
|
+
|
128
|
+
if !sources_overrides.empty? && !sources_overrides.include?(source.class.type)
|
129
|
+
report.warnings << "skipped source"
|
130
|
+
|
131
|
+
# return a symbol to speficy the source was skipped.
|
132
|
+
# This is truthy and will result in the source being considered successful
|
133
|
+
return :skipped
|
134
|
+
end
|
135
|
+
|
136
|
+
dependencies = source.dependencies.sort_by { |dependency| dependency.name }
|
137
|
+
results = dependencies.map do |dependency|
|
138
|
+
dependency_report = Licensed::Report.new(name: [report.name, dependency.name].join("."), target: dependency)
|
139
|
+
report.reports << dependency_report
|
140
|
+
run_dependency(app, source, dependency, dependency_report)
|
124
141
|
end
|
142
|
+
|
143
|
+
result = results.all?
|
144
|
+
|
145
|
+
yield(result) if block_given?
|
146
|
+
|
147
|
+
result
|
148
|
+
rescue Licensed::Shell::Error => err
|
149
|
+
report.errors << err.message
|
150
|
+
false
|
151
|
+
rescue Licensed::Sources::Source::Error => err
|
152
|
+
report.errors << err.message
|
153
|
+
false
|
154
|
+
ensure
|
155
|
+
reporter.end_report_source(source, report)
|
125
156
|
end
|
126
157
|
|
127
158
|
# Run the command for a dependency, evaluating the dependency and
|
@@ -131,27 +162,27 @@ module Licensed
|
|
131
162
|
# app - The application configuration for the dependency
|
132
163
|
# source - The dependency source enumerator for the dependency
|
133
164
|
# dependency - An application dependency
|
165
|
+
# report - A report object for this dependency
|
134
166
|
#
|
135
167
|
# Returns whether the command succeeded for the dependency
|
136
|
-
def run_dependency(app, source, dependency)
|
137
|
-
reporter.
|
138
|
-
if dependency.errors?
|
139
|
-
report.errors.concat(dependency.errors)
|
140
|
-
return false
|
141
|
-
end
|
142
|
-
|
143
|
-
begin
|
144
|
-
# allow additional report data to be given by commands
|
145
|
-
if block_given?
|
146
|
-
next true if (yield report) == :skip
|
147
|
-
end
|
168
|
+
def run_dependency(app, source, dependency, report)
|
169
|
+
reporter.begin_report_dependency(dependency, report)
|
148
170
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
false
|
153
|
-
end
|
171
|
+
if dependency.errors?
|
172
|
+
report.errors.concat(dependency.errors)
|
173
|
+
return false
|
154
174
|
end
|
175
|
+
|
176
|
+
result = evaluate_dependency(app, source, dependency, report)
|
177
|
+
|
178
|
+
yield(result) if block_given?
|
179
|
+
|
180
|
+
result
|
181
|
+
rescue Licensed::DependencyRecord::Error, Licensed::Shell::Error => err
|
182
|
+
report.errors << err.message
|
183
|
+
false
|
184
|
+
ensure
|
185
|
+
reporter.end_report_dependency(dependency, report)
|
155
186
|
end
|
156
187
|
|
157
188
|
# Evaluate a dependency for the command. Must be implemented by a command implementation.
|
@@ -165,6 +196,10 @@ module Licensed
|
|
165
196
|
def evaluate_dependency(app, source, dependency, report)
|
166
197
|
raise "`evaluate_dependency` must be implemented by a command"
|
167
198
|
end
|
199
|
+
|
200
|
+
def sources_overrides
|
201
|
+
@sources_overrides = Array(options[:sources])
|
202
|
+
end
|
168
203
|
end
|
169
204
|
end
|
170
205
|
end
|
@@ -29,12 +29,6 @@ module Licensed
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def run(**options)
|
33
|
-
super do |report|
|
34
|
-
report["git_repo"] = Licensed::Git.git_repo?
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
32
|
# Returns the default reporter to use during the command run
|
39
33
|
#
|
40
34
|
# options - The options the command was run with
|
@@ -46,11 +40,18 @@ module Licensed
|
|
46
40
|
|
47
41
|
protected
|
48
42
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
43
|
+
def run_command(report)
|
44
|
+
report["git_repo"] = Licensed::Git.git_repo?
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
def run_app(app, report)
|
49
|
+
report.merge! AppEnvironment.new(app).to_h
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_source(app, source, report)
|
54
|
+
true
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
@@ -13,25 +13,6 @@ 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
|
-
|
35
16
|
# Listing dependencies requires no extra work.
|
36
17
|
#
|
37
18
|
# app - The application configuration for the dependency
|
@@ -13,25 +13,6 @@ 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
|
-
|
35
16
|
# Load stored dependency record data to add to the notices report.
|
36
17
|
#
|
37
18
|
# app - The application configuration for the dependency
|
@@ -15,22 +15,17 @@ module Licensed
|
|
15
15
|
|
16
16
|
protected
|
17
17
|
|
18
|
-
# Run the
|
19
|
-
#
|
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
|
18
|
+
# Run the comand and set an error message to review the documentation
|
19
|
+
# when any errors have been reported
|
22
20
|
#
|
23
|
-
#
|
24
|
-
# source - A dependency source enumerator
|
21
|
+
# report - A Licensed::Report object for this command
|
25
22
|
#
|
26
|
-
# Returns whether the command succeeded
|
27
|
-
def
|
28
|
-
super do |
|
29
|
-
next if
|
30
|
-
|
31
|
-
|
32
|
-
report.warnings << "skipped source"
|
33
|
-
:skip
|
23
|
+
# Returns whether the command succeeded based on the call to super
|
24
|
+
def run_command(report)
|
25
|
+
super do |result|
|
26
|
+
next if result
|
27
|
+
|
28
|
+
report.errors << "Licensed found errors during source enumeration. Please see https://github.com/github/licensed/tree/master/docs/commands/status.md#status-errors-and-resolutions for possible resolutions."
|
34
29
|
end
|
35
30
|
end
|
36
31
|
|
@@ -47,11 +42,14 @@ module Licensed
|
|
47
42
|
def evaluate_dependency(app, source, dependency, report)
|
48
43
|
filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}")
|
49
44
|
report["filename"] = filename
|
45
|
+
report["version"] = dependency.version
|
50
46
|
|
51
47
|
cached_record = cached_record(filename)
|
52
48
|
if cached_record.nil?
|
49
|
+
report["license"] = nil
|
53
50
|
report.errors << "cached dependency record not found"
|
54
51
|
else
|
52
|
+
report["license"] = cached_record["license"]
|
55
53
|
report.errors << "cached dependency record out of date" if cached_record["version"] != dependency.version
|
56
54
|
report.errors << "missing license text" if cached_record.licenses.empty?
|
57
55
|
if cached_record["review_changed_license"]
|
@@ -61,7 +59,7 @@ module Licensed
|
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
|
-
report.errors.empty?
|
62
|
+
report["allowed"] = report.errors.empty?
|
65
63
|
end
|
66
64
|
|
67
65
|
# Returns true if a cached record needs further review based on the
|