licensed 3.1.0 → 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +19 -0
  3. data/.github/workflows/release.yml +4 -4
  4. data/.github/workflows/test.yml +169 -48
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +51 -1
  7. data/README.md +25 -80
  8. data/docker/Dockerfile.build-linux +1 -1
  9. data/docs/adding_a_new_source.md +11 -8
  10. data/docs/commands/README.md +59 -0
  11. data/docs/commands/cache.md +35 -0
  12. data/docs/commands/env.md +10 -0
  13. data/docs/commands/list.md +23 -0
  14. data/docs/commands/migrate.md +10 -0
  15. data/docs/commands/notices.md +12 -0
  16. data/docs/commands/status.md +74 -0
  17. data/docs/commands/version.md +3 -0
  18. data/docs/configuration/README.md +11 -0
  19. data/docs/configuration/allowed_licenses.md +17 -0
  20. data/docs/configuration/application_name.md +63 -0
  21. data/docs/configuration/application_source.md +64 -0
  22. data/docs/configuration/configuration_root.md +27 -0
  23. data/docs/configuration/configuring_multiple_apps.md +58 -0
  24. data/docs/configuration/dependency_source_enumerators.md +28 -0
  25. data/docs/configuration/ignoring_dependencies.md +19 -0
  26. data/docs/configuration/metadata_cache.md +106 -0
  27. data/docs/configuration/reviewing_dependencies.md +18 -0
  28. data/docs/configuration.md +9 -173
  29. data/lib/licensed/cli.rb +2 -2
  30. data/lib/licensed/commands/cache.rb +21 -20
  31. data/lib/licensed/commands/command.rb +108 -73
  32. data/lib/licensed/commands/environment.rb +12 -11
  33. data/lib/licensed/commands/list.rb +0 -19
  34. data/lib/licensed/commands/notices.rb +0 -19
  35. data/lib/licensed/commands/status.rb +13 -15
  36. data/lib/licensed/configuration.rb +77 -7
  37. data/lib/licensed/report.rb +44 -0
  38. data/lib/licensed/reporters/cache_reporter.rb +48 -64
  39. data/lib/licensed/reporters/json_reporter.rb +19 -21
  40. data/lib/licensed/reporters/list_reporter.rb +45 -58
  41. data/lib/licensed/reporters/notices_reporter.rb +33 -46
  42. data/lib/licensed/reporters/reporter.rb +37 -104
  43. data/lib/licensed/reporters/status_reporter.rb +58 -56
  44. data/lib/licensed/reporters/yaml_reporter.rb +19 -21
  45. data/lib/licensed/sources/bundler/definition.rb +36 -0
  46. data/lib/licensed/sources/bundler/missing_specification.rb +10 -7
  47. data/lib/licensed/sources/bundler.rb +34 -70
  48. data/lib/licensed/sources/dep.rb +2 -2
  49. data/lib/licensed/sources/go.rb +3 -3
  50. data/lib/licensed/sources/gradle.rb +2 -2
  51. data/lib/licensed/sources/helpers/content_versioning.rb +2 -1
  52. data/lib/licensed/sources/npm.rb +4 -3
  53. data/lib/licensed/sources/nuget.rb +1 -2
  54. data/lib/licensed/version.rb +1 -1
  55. data/lib/licensed.rb +1 -0
  56. data/licensed.gemspec +4 -4
  57. data/script/source-setup/go +1 -1
  58. metadata +45 -13
  59. data/docs/commands.md +0 -95
@@ -6,66 +6,47 @@ module Licensed
6
6
  TEXT_SEPARATOR = "\n\n#{("-" * 5)}\n\n".freeze
7
7
  LICENSE_SEPARATOR = "\n#{("*" * 5)}\n".freeze
8
8
 
9
- # Reports on an application configuration in a notices command run
9
+ # Reports the start of an application evaluation in a notices command run
10
10
  #
11
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
12
+ # report - A report object containing information about the app evaluation
13
+ def begin_report_app(app, report)
14
+ shell.info "Writing notices for #{app["name"]} to #{app_notices_path(app)}"
15
+ end
31
16
 
32
- result
17
+ # Writes the licensing information gathered during the application evaluation
18
+ # to a notices file
19
+ #
20
+ # app - An application configuration
21
+ # report - A report object containing information about the app evaluation
22
+ def end_report_app(app, report)
23
+ File.open(app_notices_path(app), "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)
33
30
  end
34
31
  end
35
32
 
36
-
37
- # Reports on a dependency source enumerator in a notices command run.
38
- # Shows warnings encountered during the run.
33
+ # Reports any warnings encountered during the run.
39
34
  #
40
35
  # 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
36
+ # report - A report object containing information about the source evaluation
37
+ def end_report_source(source, report)
38
+ report.warnings.each do |warning|
39
+ shell.warn "* #{report.name}: #{warning}"
53
40
  end
54
41
  end
55
42
 
56
43
  # Reports on a dependency in a notices command run.
57
44
  #
58
45
  # 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
46
+ # report - A report object containing information about the dependency evaluation
47
+ def end_report_dependency(dependency, report)
48
+ report.warnings.each do |warning|
49
+ shell.warn "* #{report.name}: #{warning}"
69
50
  end
70
51
  end
71
52
 
@@ -94,6 +75,12 @@ module Licensed
94
75
  #{texts.map(&:strip).reject(&:empty?).compact.join(TEXT_SEPARATOR)}
95
76
  NOTICE
96
77
  end
78
+
79
+ # Returns the path to an applications notices file
80
+ def app_notices_path(app)
81
+ filename = app["shared_cache"] ? "NOTICE.#{app["name"]}" : "NOTICE"
82
+ app.cache_path.join(filename)
83
+ end
97
84
  end
98
85
  end
99
86
  end
@@ -2,133 +2,66 @@
2
2
  module Licensed
3
3
  module Reporters
4
4
  class Reporter
5
- class Report < Hash
6
- attr_reader :name
7
- attr_reader :target
8
- def initialize(name:, target:)
9
- super()
10
- @name = name
11
- @target = target
12
- end
13
-
14
- def reports
15
- @reports ||= []
16
- end
17
-
18
- def errors
19
- @errors ||= []
20
- end
21
-
22
- def warnings
23
- @warnings ||= []
24
- end
25
-
26
- def all_reports
27
- result = []
28
- result << self
29
- result.push(*reports.flat_map(&:all_reports))
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
44
- end
45
-
46
5
  class ReportingError < StandardError; end;
47
6
 
48
7
  def initialize(shell = Licensed::UI::Shell.new)
49
8
  @shell = shell
50
- @run_report = nil
51
- @app_report = nil
52
- @source_report = nil
53
9
  end
54
10
 
55
- # Generate a report for a licensed command execution
56
- # Yields a report object which can be used to view or add
57
- # data generated for this run
11
+ # Report the beginning of a command evaluation
58
12
  #
59
- # Returns the result of the yielded method
60
- def report_run(command)
61
- result = nil
62
- @run_report = Report.new(name: nil, target: command)
63
- begin
64
- result = yield @run_report
65
- ensure
66
- @run_report = nil
67
- end
13
+ # command - The command being run
14
+ # report - A report object containing information about the command run
15
+ def begin_report_command(command, report)
16
+ end
68
17
 
69
- result
18
+ # Report the end of a command evaluation
19
+ #
20
+ # command - The command being run
21
+ # report - A report object containing information about the command run
22
+ def end_report_command(command, report)
70
23
  end
71
24
 
72
- # Generate a report for a licensed app configuration
73
- # Yields a report object which can be used to view or add
74
- # data generated for this app
25
+ # Report the beginning of an app evaluation
75
26
  #
76
27
  # app - An application configuration
77
- #
78
- # Returns the result of the yielded method
79
- # Note - must be called from inside the `report_run` scope
80
- def report_app(app)
81
- raise ReportingError.new("Cannot call report_app with active app context") unless @app_report.nil?
82
- raise ReportingError.new("Call report_run before report_app") if @run_report.nil?
83
- result = nil
84
- @app_report = Report.new(name: app["name"], target: app)
85
- begin
86
- result = yield @app_report
87
- ensure
88
- @run_report.reports << @app_report
89
- @app_report = nil
90
- end
28
+ # report - A report object containing information about the app evaluation
29
+ def begin_report_app(app, report)
30
+ end
91
31
 
92
- result
32
+ # Report the end of an app evaluation
33
+ #
34
+ # app - An application configuration
35
+ # report - A report object containing information about the app evaluation
36
+ def end_report_app(app, report)
93
37
  end
94
38
 
95
- # Generate a report for a licensed dependency source enumerator
96
- # Yields a report object which can be used to view or add
97
- # data generated for this dependency source
39
+ # Report the beginning of a source evaluation
98
40
  #
99
41
  # source - A dependency source enumerator
100
- #
101
- # Returns the result of the yielded method
102
- # Note - must be called from inside the `report_app` scope
103
- def report_source(source)
104
- raise ReportingError.new("Cannot call report_source with active source context") unless @source_report.nil?
105
- raise ReportingError.new("Call report_app before report_source") if @app_report.nil?
106
- result = nil
107
- @source_report = Report.new(name: [@app_report.name, source.class.type].join("."), target: source)
108
- begin
109
- result = yield @source_report
110
- ensure
111
- @app_report.reports << @source_report
112
- @source_report = nil
113
- end
42
+ # report - A report object containing information about the source evaluation
43
+ def begin_report_source(source, report)
44
+ end
114
45
 
115
- result
46
+ # Report the end of a source evaluation
47
+ #
48
+ # source - A dependency source enumerator
49
+ # report - A report object containing information about the source evaluation
50
+ def end_report_source(source, report)
116
51
  end
117
52
 
118
- # Generate a report for a licensed dependency
119
- # Yields a report object which can be used to view or add
120
- # data generated for this dependency
53
+ # Report the beginning of a dependency evaluation
121
54
  #
122
55
  # dependency - An application dependency
123
- #
124
- # Returns the result of the yielded method
125
- # Note - must be called from inside the `report_source` scope
126
- def report_dependency(dependency)
127
- raise ReportingError.new("Call report_source before report_dependency") if @source_report.nil?
56
+ # source - A report object containing information about the dependency evaluation
57
+ def begin_report_dependency(dependency, report)
58
+ end
128
59
 
129
- dependency_report = Report.new(name: [@source_report.name, dependency.name].join("."), target: dependency)
130
- @source_report.reports << dependency_report
131
- yield dependency_report
60
+ # Report the end of a dependency evaluation
61
+ #
62
+ # dependency - An application dependency
63
+ # source - A report object containing information about the dependency evaluation
64
+ def end_report_dependency(dependency, report)
132
65
  end
133
66
 
134
67
  protected
@@ -3,80 +3,82 @@
3
3
  module Licensed
4
4
  module Reporters
5
5
  class StatusReporter < Reporter
6
- # Generate a report for a licensed status command run
7
- # Shows the errors found when checking status, as well as
8
- # overall number of dependencies checked
6
+ # Reports any errors encountered at the command level
9
7
  #
10
- # Returns the result of the yielded method
11
- def report_app(app)
12
- super do |report|
13
- shell.info "Checking cached dependency records for #{app["name"]}"
8
+ # command - The command being run
9
+ # report - A report object containing information about the command run
10
+ def end_report_command(command, report)
11
+ if report.errors.any?
12
+ shell.newline
13
+ report.errors.each { |e| shell.error e }
14
+ end
15
+ end
14
16
 
15
- result = yield report
17
+ # Reports the start of checking records for an app
18
+ #
19
+ # app - An application configuration
20
+ # report - A report containing information about the app evaluation
21
+ def begin_report_app(app, report)
22
+ shell.info "Checking cached dependency records for #{app["name"]}"
23
+ end
16
24
 
17
- all_reports = report.all_reports
25
+ # Reports any errors found when checking status, as well as
26
+ # overall number of dependencies checked
27
+ #
28
+ # app - An application configuration
29
+ # report - A report containing information about the app evaluation
30
+ def end_report_app(app, report)
31
+ all_reports = report.all_reports
18
32
 
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(", ")
33
+ warning_reports = all_reports.select { |r| r.warnings.any? }.to_a
34
+ if warning_reports.any?
35
+ shell.newline
36
+ shell.warn "Warnings:"
37
+ warning_reports.each do |r|
38
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
25
39
 
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
40
+ shell.warn "* #{r.name}"
41
+ shell.warn " #{display_metadata}" unless display_metadata.empty?
42
+ r.warnings.each do |warning|
43
+ shell.warn " - #{warning}"
32
44
  end
45
+ shell.newline
33
46
  end
47
+ end
34
48
 
35
- errored_reports = all_reports.select { |r| r.errors.any? }.to_a
49
+ errored_reports = all_reports.select { |r| r.errors.any? }.to_a
36
50
 
37
- dependency_count = all_reports.select { |r| r.target.is_a?(Licensed::Dependency) }.size
38
- error_count = errored_reports.sum { |r| r.errors.size }
51
+ dependency_count = all_reports.count { |r| r.target.is_a?(Licensed::Dependency) }
52
+ error_count = errored_reports.sum { |r| r.errors.size }
39
53
 
40
- if error_count > 0
41
- shell.newline
42
- shell.error "Errors:"
43
- errored_reports.each do |r|
44
- display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
54
+ if error_count > 0
55
+ shell.newline
56
+ shell.error "Errors:"
57
+ errored_reports.each do |r|
58
+ display_metadata = r.map { |k, v| "#{k}: #{v}" }.join(", ")
45
59
 
46
- shell.error "* #{r.name}"
47
- shell.error " #{display_metadata}" unless display_metadata.empty?
48
- r.errors.each do |error|
49
- shell.error " - #{error}"
50
- end
51
- shell.newline
60
+ shell.error "* #{r.name}"
61
+ shell.error " #{display_metadata}" unless display_metadata.empty?
62
+ r.errors.each do |error|
63
+ shell.error " - #{error}"
52
64
  end
65
+ shell.newline
53
66
  end
54
-
55
- shell.newline
56
- shell.info "#{dependency_count} dependencies checked, #{error_count} errors found."
57
-
58
- result
59
67
  end
68
+
69
+ shell.newline
70
+ shell.info "#{dependency_count} dependencies checked, #{error_count} errors found."
60
71
  end
61
72
 
62
- # Reports on a dependency in a status command run.
63
- # Shows whether the dependency's status is valid in dot format
73
+ # Reports whether the dependency's status is valid in dot format
64
74
  #
65
75
  # dependency - An application dependency
66
- #
67
- # Returns the result of the yielded method
68
- # Note - must be called from inside the `report_run` scope
69
- def report_dependency(dependency)
70
- super do |report|
71
- result = yield report
72
-
73
- if report.errors.empty?
74
- shell.confirm(".", false)
75
- else
76
- shell.error("F", false)
77
- end
78
-
79
- result
76
+ # report - A report containing information about the dependency evaluation
77
+ def end_report_dependency(dependency, report)
78
+ if report.errors.empty?
79
+ shell.confirm(".", false)
80
+ else
81
+ shell.error("F", false)
80
82
  end
81
83
  end
82
84
  end
@@ -2,31 +2,29 @@
2
2
  module Licensed
3
3
  module Reporters
4
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
5
+ # Report all information from the command run to the shell as a YAML object
6
+ #
7
+ # command - The command being run
8
+ # report - A report object containing information about the command run
9
+ def end_report_command(command, report)
10
+ report["apps"] = report.reports.map(&:to_h) if report.reports.any?
11
+ shell.info sanitize(report.to_h).to_yaml
14
12
  end
15
13
 
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
14
+ # Add source report information to the app report hash
15
+ #
16
+ # app - An application configuration
17
+ # report - A report object containing information about the app evaluation
18
+ def end_report_app(app, report)
19
+ report["sources"] = report.reports.map(&:to_h) if report.reports.any?
22
20
  end
23
21
 
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
22
+ # Add dependency report information to the source report hash
23
+ #
24
+ # source - A dependency source enumerator
25
+ # report - A report object containing information about the source evaluation
26
+ def end_report_source(source, report)
27
+ report["dependencies"] = report.reports.map(&:to_h) if report.reports.any?
30
28
  end
31
29
 
32
30
  def sanitize(object)