licensed 1.5.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +22 -1
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +17 -24
  6. data/Rakefile +2 -2
  7. data/docs/adding_a_new_source.md +93 -0
  8. data/docs/commands.md +81 -0
  9. data/docs/configuration.md +8 -8
  10. data/docs/migrating_to_newer_versions.md +3 -0
  11. data/docs/reporters.md +174 -0
  12. data/docs/sources/bundler.md +5 -5
  13. data/lib/licensed.rb +5 -14
  14. data/lib/licensed/cli.rb +23 -9
  15. data/lib/licensed/commands.rb +9 -0
  16. data/lib/licensed/commands/cache.rb +82 -0
  17. data/lib/licensed/commands/command.rb +112 -0
  18. data/lib/licensed/commands/list.rb +24 -0
  19. data/lib/licensed/commands/status.rb +49 -0
  20. data/lib/licensed/configuration.rb +3 -8
  21. data/lib/licensed/dependency.rb +116 -58
  22. data/lib/licensed/dependency_record.rb +76 -0
  23. data/lib/licensed/migrations.rb +7 -0
  24. data/lib/licensed/migrations/v2.rb +65 -0
  25. data/lib/licensed/reporters.rb +9 -0
  26. data/lib/licensed/reporters/cache_reporter.rb +76 -0
  27. data/lib/licensed/reporters/list_reporter.rb +69 -0
  28. data/lib/licensed/reporters/reporter.rb +119 -0
  29. data/lib/licensed/reporters/status_reporter.rb +67 -0
  30. data/lib/licensed/shell.rb +8 -10
  31. data/lib/licensed/sources.rb +15 -0
  32. data/lib/licensed/{source → sources}/bower.rb +14 -19
  33. data/lib/licensed/{source → sources}/bundler.rb +73 -48
  34. data/lib/licensed/{source → sources}/cabal.rb +40 -46
  35. data/lib/licensed/{source → sources}/dep.rb +15 -27
  36. data/lib/licensed/{source → sources}/git_submodule.rb +14 -19
  37. data/lib/licensed/{source → sources}/go.rb +28 -35
  38. data/lib/licensed/{source → sources}/manifest.rb +68 -90
  39. data/lib/licensed/{source → sources}/npm.rb +16 -25
  40. data/lib/licensed/{source → sources}/pip.rb +23 -25
  41. data/lib/licensed/sources/source.rb +69 -0
  42. data/lib/licensed/ui/shell.rb +4 -0
  43. data/lib/licensed/version.rb +6 -1
  44. data/licensed.gemspec +4 -4
  45. data/script/source-setup/bundler +1 -1
  46. metadata +32 -18
  47. data/lib/licensed/command/cache.rb +0 -82
  48. data/lib/licensed/command/list.rb +0 -43
  49. data/lib/licensed/command/status.rb +0 -79
  50. data/lib/licensed/command/version.rb +0 -18
  51. data/lib/licensed/license.rb +0 -68
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87be3d9de274a4f66698f8880f5c858c2733c35f
4
- data.tar.gz: eb8125c0b348a042e814bf72732e1fbdce0e4426
3
+ metadata.gz: cd572795c842f263e5fc3c180b1bf716404b9021
4
+ data.tar.gz: '094c5d5227704cbac518df12e20b05456a4bba03'
5
5
  SHA512:
6
- metadata.gz: 53376c057796cd662142d49b5122101d70d6ffc759f945d2da2d26ef0c72f403e5b07a92c8d367aecfcd1f0efa4706a893035d6f9671cb3bddaa948707b05b1b
7
- data.tar.gz: ceff661d0fdfda3bfb0920cf246cce9220a13c7675e1547b8be6c3ae8d9f29bb2e78e5541e56c3af3d388a16b5944adb11324e6191afb19d9c9cf95c8aa7086f
6
+ metadata.gz: be757c8f540285eaa610799963f184522e923c14bdb54d6250709511a13e6f08d3cac1da1e72b5d625687a5b0b4b874cfab50f8589ad3614cf2673a8b1781766
7
+ data.tar.gz: 836885af14623a25feb9ebaf8a697a9c7878bd9bc839615c4dc5e685f913059ddeb93b122b9b7ba19a2419965b2a8009c2d6f8594cbafcba922f2259505d1a72
data/.gitignore CHANGED
@@ -23,6 +23,8 @@ test/fixtures/cabal/*
23
23
  !test/fixtures/cabal/app*
24
24
  test/fixtures/git_submodule/*
25
25
  !test/fixtures/git_submodule/README
26
+ test/fixtures/pip/venv
27
+ !test/fixtures/migrations/**/*
26
28
 
27
29
  vendor/licenses
28
30
  .licenses
@@ -6,6 +6,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.0.0 - 2019-02-09
10
+
11
+ **This is a major release and includes breaking changes to the configuration and cached record file formats**
12
+
13
+ ### Added
14
+ - New `migrate` command to automatically update configuration and cached record file formats
15
+ - New extensible reporting infrastructure
16
+ - New base command and source classes to abstract away implementation details
17
+
18
+ ### Changes
19
+ - Cached dependency metadata files are now stored entirely as YAML, with `.dep.yml` extension
20
+ - The Bundler dependency source is now identified in configuration files and output as `bundler` instead of `rubygem`
21
+ - Refactored sources for better consistency between classes
22
+ - Refactored commands for better consistency between classes
23
+ - Command outputs have changed for better consistency
24
+ - Updated Dependency classes for better integration with `licensee`
25
+
26
+ ### Fixed
27
+ - Licensed no longer exits on errors when evaluating dependency sources or finding dependencies
28
+ - The Bundler dependency source correctly finds the `bundler` gem as a dependency in more cases
29
+
9
30
  ## 1.5.2 - 2018-12-27
10
31
 
11
32
  ### Changes
@@ -112,4 +133,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
112
133
 
113
134
  Initial release :tada:
114
135
 
115
- [Unreleased]: https://github.com/github/licensed/compare/1.5.2...HEAD
136
+ [Unreleased]: https://github.com/github/licensed/compare/2.0.0...HEAD
@@ -13,8 +13,8 @@ Please note that this project is released with a [Contributor Code of Conduct][c
13
13
 
14
14
  0. [Fork][fork] and clone the repository
15
15
  0. Configure and install the dependencies: `script/bootstrap`
16
- 0. Setup test fixtures: `rake setup`
17
- 0. Make sure the tests pass on your machine: `rake test`
16
+ 0. Setup test fixtures: `bundle exec rake setup`
17
+ 0. Make sure the tests pass on your machine: `bundle exec rake test`
18
18
  0. Create a new branch: `git checkout -b my-branch-name`
19
19
  0. Make your change, add tests, and make sure the tests still pass
20
20
  0. Push to your fork and [submit a pull request][pr]
data/README.md CHANGED
@@ -12,6 +12,13 @@ Licensed is **not** a complete open source license compliance solution. Please u
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
 
15
+ ## Licensed v2
16
+
17
+ Licensed v2 includes many internal changes intended to make licensed more extensible and easier to update in the future. While not too much has changed externally, v2 is incompatible with configuration files and cached records from previous versions. Fortunately, migrating is easy using the `licensed migrate` command.
18
+
19
+ See [CHANGELOG.md](./CHANGELOG.md) for more details on whats changed.
20
+ See the [migration documentation](./docs/migrating_to_newer_versions.md) for more info on migrating to v2, or run `licensed help migrate`.
21
+
15
22
  ## Installation
16
23
 
17
24
  ### With a Gemfile
@@ -50,32 +57,12 @@ For example, on macOS with Homebrew: `brew install cmake pkg-config` and on Ubun
50
57
  ## Usage
51
58
 
52
59
  - `licensed list`: Output enumerated dependencies only.
53
-
54
60
  - `licensed cache`: Cache licenses and metadata.
55
-
56
61
  - `licensed status`: Check status of dependencies' cached licenses. For example:
57
-
58
- ```
59
- $ bundle exec licensed status
60
- Checking licenses for 3 dependencies
61
-
62
- Warnings:
63
-
64
- .licenses/rubygem/bundler.txt:
65
- - license needs reviewed: mit.
66
-
67
- .licenses/rubygem/licensee.txt:
68
- - cached license data missing
69
-
70
- .licenses/bower/jquery.txt:
71
- - license needs reviewed: mit.
72
- - cached license data out of date
73
-
74
- 3 dependencies checked, 3 warnings found.
75
- ```
76
-
77
62
  - `licensed version`: Show current installed version of Licensed. Aliases: `-v|--version`
78
63
 
64
+ See the [commands documentation](./docs/commands.md) for additional documentation, or run `licensed -h` to see all of the current available commands.
65
+
79
66
  ### Configuration
80
67
 
81
68
  All commands, except `version`, accept a `-c|--config` option to specify a path to a configuration file or directory.
@@ -93,7 +80,7 @@ See the [configuration file documentation](./docs/configuration.md) for more det
93
80
 
94
81
  Dependencies will be automatically detected for all of the following sources by default.
95
82
  1. [Bower (bower)](./docs/sources/bower.md)
96
- 2. [Bundler (rubygem)](./docs/sources/bundler.md)
83
+ 2. [Bundler](./docs/sources/bundler.md)
97
84
  3. [Cabal (cabal)](./docs/sources/cabal.md)
98
85
  4. [Go (go)](./docs/sources/go.md)
99
86
  5. [Go Dep (dep)](./docs/sources/dep.md)
@@ -106,7 +93,7 @@ You can disable any of them in the configuration file:
106
93
 
107
94
  ```yml
108
95
  sources:
109
- rubygem: false
96
+ bundler: false
110
97
  npm: false
111
98
  bower: false
112
99
  cabal: false
@@ -138,6 +125,12 @@ if Licensed::Shell.tool_available?('bundle')
138
125
  end
139
126
  ```
140
127
 
128
+ See the [documentation on adding new sources](./docs/adding_a_new_source.md) for more information.
129
+
130
+ #### Adding Commands
131
+
132
+ See the [documentation on commands](./docs/commands.md) for information about adding a new CLI command.
133
+
141
134
  ## Contributing
142
135
 
143
136
  Bug reports and pull requests are welcome on GitHub at https://github.com/github/licensed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org/) code of conduct. See [CONTRIBUTING](CONTRIBUTING.md) for more details.
data/Rakefile CHANGED
@@ -27,7 +27,7 @@ task :setup, [:arguments] do |task, args|
27
27
  end
28
28
  end
29
29
 
30
- sources_search = File.expand_path("lib/licensed/source/*.rb", __dir__)
30
+ sources_search = File.expand_path("lib/licensed/sources/*.rb", __dir__)
31
31
  sources = Dir[sources_search].map { |f| File.basename(f, ".*") }
32
32
 
33
33
  namespace :test do
@@ -47,7 +47,7 @@ namespace :test do
47
47
 
48
48
  # use negative lookahead to exclude all source tests except
49
49
  # the tests for `source`
50
- t.test_files = FileList["test/**/*_test.rb"].exclude(/test\/source\/(?!#{source}).*?_test.rb/,
50
+ t.test_files = FileList["test/**/*_test.rb"].exclude(/test\/sources\/(?!#{source}).*?_test.rb/,
51
51
  "test/fixtures/**/*_test.rb")
52
52
  end
53
53
  end
@@ -0,0 +1,93 @@
1
+ # Adding a new source dependency enumerator
2
+
3
+ ## Implement new `Source` class
4
+
5
+ Dependency enumerators inherit and override the [`Licensed::Sources::Source`](../lib/licensed/sources/source.rb) class.
6
+
7
+ #### Required method overrides
8
+ 1. `Licensed::Sources::Source#enabled?`
9
+ - Returns whether dependencies can be enumerated in the current environment.
10
+ 2. `Licensed::Sources::Source#enumerate_dependencies`
11
+ - Returns an enumeration of `Licensed::Dependency` objects found which map to the dependencies of the current project.
12
+
13
+ #### Optional method overrides
14
+ 1. `Licensed::Sources::Source.type`
15
+ - Returns the name of the current dependency enumerator as it is found in a licensed configuration file.
16
+
17
+ ## Determining if dependencies should be enumerated
18
+
19
+ This section covers the `Licensed::Sources::Source#enabled?` method. This method should return a truthy/falsey value indicating
20
+ whether `Licensed::Source::Sources#enumerate_dependencies` should be called on the current dependency source object.
21
+
22
+ Determining whether dependencies should be enumerated depends on whether all the tools or files needed to find dependencies are present.
23
+ For example, to enumerate `npm` dependencies the `npm` CLI tool must be found with `Licensed::Shell.tool_available?` and a `package.json` file needs to exist in the licensed app's configured [`source_path`](./configuration.md#configuration-paths).
24
+
25
+ #### Gating functionality when required tools are not available.
26
+
27
+ When adding new dependency sources, ensure that `script/bootstrap` scripting and tests are only run if the required tooling is available on the development machine.
28
+
29
+ * See `script/bootstrap` for examples of gating scripting based on whether tooling executables are found.
30
+ * Use `Licensed::Shell.tool_available?` when writing test files to gate running a test suite when tooling executables aren't available.
31
+ ```ruby
32
+ if Licensed::Shell.tool_available?('bundle')
33
+ describe Licensed::Source::Bundler do
34
+ ...
35
+ end
36
+ end
37
+ ```
38
+
39
+ ## Enumerating dependencies
40
+
41
+ This section covers the `Licensed::Sources::Source#enumerate_dependencies` method. This method should return an enumeration of
42
+ `Licensed::Dependency` objects.
43
+
44
+ Enumerating dependencies will require some knowledge of the package manager, language or framework that manages the dependencies.
45
+
46
+ Relying on external tools always has a risk that the tool could change. It's generally preferred to not rely on package manager files
47
+ or other implementation details as these could change over time. CLI tools that provides the necessary information are generally preferred
48
+ as they will more likely have requirements for backwards compatibility.
49
+
50
+ #### Creating dependency objects
51
+
52
+ Creating a new `Licensed::Dependency` object requires name, version, and path arguments. Dependency objects optionally accept a path to use as search root when finding licenses along with any other metadata that is useful to identify the dependency.
53
+
54
+ ##### `Licensed::Dependency` arguments
55
+
56
+ 1. name (required)
57
+ - The name of the dependency. Together with the version, this should uniquely identify the dependency.
58
+ 2. version (required)
59
+ - The current version of the dependency, used to determine when a dependency has changed. Together with the name, this should uniquely identify the dependency.
60
+ 3. path (required)
61
+ - A path used by [`Licensee`](https://github.com/benbalter/licensee) to find dependency license content. Can be either a folder or a file.
62
+ 4. search_root (optional)
63
+ - The root of the directory hierarchy to search for a license file.
64
+ 5. metadata (optional)
65
+ - Any additional metadata that would be useful in identifying the dependency.
66
+ - suggested metadata
67
+ 1. summary
68
+ - A short description of the dependencies purpose.
69
+ 2. homepage
70
+ - The dependency's homepage.
71
+ 6. errors (optional)
72
+ - Any errors found when loading dependency information.
73
+
74
+ #### Finding licenses
75
+
76
+ In some cases, license content will be in a parent directory of the specified location. For instance, this can happen with Golang packages
77
+ that share a license file, e.g. `github.com/go/pkg/1` and `github.com/go/pkg/2` might share a license at `github.com/go/pkg`. In this case, create a `Licensed::Dependency` with the optional `search_root` property, which denotes the root of the directory hierarchy that should be searched. Directories will be examined in order from the given license location to the `search_root` location to prefer license files with more specificity, i.e. `github.com/go/pkg/1` will be searched before `github.com/go/pkg`.
78
+
79
+ #### Handling errors when enumerating dependencies
80
+
81
+ External tools have their own error handling which, if left unhandled, can cause dependency enumeration as a whole to fail either for an individual dependency source or for licensed as a whole. These errors should be gracefully handled to allow for the best possible user experience.
82
+
83
+ ##### Handling errors related to a specific dependency
84
+
85
+ `Licensed::Dependency#initialize` will already set errors related to `nil` or empty `path:` arguments, as well as paths that don't exist. Additional errors can be set to a dependency using the `errors:` argument, e.g. `Licensed::Dependency.new(errors: ["error"])`.
86
+
87
+ When a dependency contains errors, all errors will be reported to the user and `Licensed::Command::Command#evaluate_dependency` will be not be called.
88
+
89
+ ##### Handling errors related to source evaluation
90
+
91
+ When an error occurs related to a specific source, raise a `Licensed::Sources::Source::Error` with an informative message. The error will be caught and reported to the user, and further evaluation of the source will be halted.
92
+
93
+ As an example, this could be useful if a source is enabled but incorrectly configured.
@@ -0,0 +1,81 @@
1
+ # Commands
2
+
3
+ Run `licensed -h` to see help content for running licensed commands.
4
+
5
+ ## `list`
6
+
7
+ Running the list command finds the dependencies for all sources in all configured applications. No additional actions are taken on each dependency.
8
+
9
+ ## `cache`
10
+
11
+ The cache command finds all dependencies and ensures that each dependency has an up-to-date cached record.
12
+
13
+ Dependency records will be saved if:
14
+ 1. The `force` option is set
15
+ 2. No cached record is found
16
+ 3. The cached record's version is different than the current dependency's version
17
+ - If the cached record's license text contents matches the current dependency's license text then the `license` metadata from the cached record is retained for the new saved record.
18
+
19
+ After the cache command is run, any cached records that don't match up to a current application dependency will be deleted.
20
+
21
+ ## `status`
22
+
23
+ The status command finds all dependencies and checks whether each dependency has a valid cached record.
24
+
25
+ A dependency will fail the status checks if:
26
+ 1. No cached record is found
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
29
+ 4. The cached record's `license` metadata doesn't match an `allowed` license from the dependency's application configuration.
30
+
31
+ ## `version`
32
+
33
+ Displays the current licensed version.
34
+
35
+ # Adding a new command
36
+
37
+ ## Implement new `Command` class
38
+
39
+ Licensed commands inherit and override the [`Licensed::Sources::Command`](../lib/licensed/commands/command.rb) class.
40
+
41
+ #### Required method overrides
42
+ 1. `Licensed::Commands::Command#evaluate_dependency`
43
+ - Runs a command execution on an application dependency.
44
+
45
+ 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
+
47
+ #### Optional method overrides
48
+
49
+ The following methods break apart the different levels of command execution. Each method wraps lower levels of command execution in a corresponding reporter method.
50
+
51
+ 1. `Licensed::Commands::Command#run`
52
+ - Runs `run_app` for each application configuration found. Wraps the execution of all applications in `Reporter#report_run`.
53
+ 2. `Licensed::Commands::Command#run_app`
54
+ - Runs `run_source` for each dependency source enumerator enabled for the application configuration. Wraps the execution of all sources in `Reporter#report_app`.
55
+ 3. `Licensed::Commands::Command#run_source`
56
+ - Runs `run_dependency` for each dependency found in the source. Wraps the execution of all dependencies in `Reporter#report_source`.
57
+ 4. `Licensed::Commands::Command#run_dependency`
58
+ - Runs `evaluate_dependency` for the dependency. Wraps the execution of all dependencies in `Reporter#report_dependency`.
59
+
60
+ As an example, `Licensed::Commands::Command#run_app` calls `Reporter#report_app` to wrap every call to `Licensed::Commands::Command#run_source`.
61
+
62
+ ##### Overriding optional methods
63
+
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.
65
+
66
+ ```ruby
67
+ def run_app(app)
68
+ 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
79
+ end
80
+ end
81
+ ```
@@ -32,7 +32,7 @@ it may still determine that it can't enumerate dependencies for a project.
32
32
  ```yml
33
33
  sources:
34
34
  bower: true
35
- rubygem: false
35
+ bundler: false
36
36
  ```
37
37
 
38
38
  `licensed` determines which sources will try to enumerate dependencies based on the following rules:
@@ -76,7 +76,7 @@ source_path: 'relative/path/to/source'
76
76
  # Sources of metadata
77
77
  sources:
78
78
  bower: true
79
- rubygem: false
79
+ bundler: false
80
80
 
81
81
  # Dependencies with these licenses are allowed by default.
82
82
  allowed:
@@ -88,7 +88,7 @@ allowed:
88
88
 
89
89
  # These dependencies are explicitly ignored.
90
90
  ignored:
91
- rubygem:
91
+ bundler:
92
92
  - some-internal-gem
93
93
 
94
94
  bower:
@@ -96,7 +96,7 @@ ignored:
96
96
 
97
97
  # These dependencies have been reviewed.
98
98
  reviewed:
99
- rubygem:
99
+ bundler:
100
100
  - bcrypt-ruby
101
101
 
102
102
  bower:
@@ -122,14 +122,14 @@ Here are some examples:
122
122
  ```yml
123
123
  sources:
124
124
  go: true
125
- rubygem: false
125
+ bundler: false
126
126
 
127
127
  ignored:
128
- rubygem:
128
+ bundler:
129
129
  - some-internal-gem
130
130
 
131
131
  reviewed:
132
- rubygem:
132
+ bundler:
133
133
  - bcrypt-ruby
134
134
 
135
135
  cache_path: 'path/to/cache'
@@ -137,7 +137,7 @@ apps:
137
137
  - source_path: 'path/to/app1'
138
138
  - source_path: 'path/to/app2'
139
139
  sources:
140
- rubygem: true
140
+ bundler: true
141
141
  go: false
142
142
  ```
143
143
 
@@ -0,0 +1,3 @@
1
+ # Migrating your licensed configuration and cached records to the latest version of licensed
2
+
3
+ Licensed v2+ ships with an additional executable, `licensed-migrator`, that can be used to update your licensed files to the format expected by the currently installed version. To run, execute `licensed migrate --from v1 -c <path to licensed configuration file>`, replacing `v1` with the major version of licensed to migrate from.
@@ -0,0 +1,174 @@
1
+ # Licensed Command Reporters
2
+
3
+ Reporters are responsible for providing feedback for a command execution. They have
4
+ access points for each level of data encountered when executing a command.
5
+ ```
6
+ command run
7
+ |
8
+ | - app
9
+ |
10
+ | - source
11
+ |
12
+ | - dependency
13
+ ```
14
+
15
+ ## Reporters
16
+
17
+ ### Cache reporter
18
+
19
+ This reporter presents the results of running a cache command in a human-readable format.
20
+ It outputs the name for each app configuration and dependency source, as well
21
+ as showing whether a dependency was cached or if a cached record was found and reused.
22
+
23
+ example output
24
+ ```
25
+ Caching dependency records for licensed
26
+ bundler
27
+ Caching licensee (9.11.0)
28
+ Caching thor (0.20.3)
29
+ Caching pathname-common_prefix (0.0.1)
30
+ Caching tomlrb (1.2.8)
31
+ Caching bundler (1.16.3)
32
+ Caching dotenv (2.6.0)
33
+ Caching octokit (4.8.0)
34
+ Caching rugged (0.27.7)
35
+ Caching sawyer (0.8.1)
36
+ Caching addressable (2.5.2)
37
+ Caching faraday (0.15.4)
38
+ Caching public_suffix (3.0.3)
39
+ Caching multipart-post (2.0.0)
40
+ * 13 bundler dependencies
41
+ ```
42
+
43
+ ### List reporter
44
+
45
+ This reporter presents the results of running a list command in a human-readable format.
46
+ It outputs the name for each app configuration and dependency source, as well
47
+ the name and version of each dependency found.
48
+
49
+ example output
50
+ ```
51
+ Listing dependencies for licensed
52
+ bundler
53
+ addressable (2.5.2)
54
+ bundler (1.16.3)
55
+ dotenv (2.6.0)
56
+ faraday (0.15.4)
57
+ licensee (9.11.0)
58
+ multipart-post (2.0.0)
59
+ octokit (4.8.0)
60
+ pathname-common_prefix (0.0.1)
61
+ public_suffix (3.0.3)
62
+ rugged (0.27.7)
63
+ sawyer (0.8.1)
64
+ thor (0.20.3)
65
+ tomlrb (1.2.8)
66
+ * 13 bundler dependencies
67
+ ```
68
+
69
+ ### Status reporter
70
+
71
+ This reporter presents the results of running a status command in a human-readable format.
72
+ It outputs the name for each app configuration and dependency source, as well
73
+ as whether each cached dependency record has any errors using a dot format.
74
+ All errors found are displayed as well.
75
+
76
+ example output
77
+ ```
78
+ Checking cached dependency records for licensed
79
+ ..F.F....F...
80
+
81
+ Errors:
82
+
83
+ * bundler.pathname-common_prefix
84
+ filename: /Users/jonabc/github/licensed/.licenses/bundler/pathname-common_prefix.dep.yml
85
+ - license needs review: other
86
+
87
+ * bundler.bundler
88
+ filename: /Users/jonabc/github/licensed/.licenses/bundler/bundler.dep.yml
89
+ - cached dependency record not found
90
+
91
+ * bundler.addressable
92
+ filename: /Users/jonabc/github/licensed/.licenses/bundler/addressable.dep.yml
93
+ - license needs review: apache-2.0
94
+ ```
95
+
96
+ ## Creating a new reporter
97
+
98
+ For examples of reporters, please see [`lib/licensed/reporters`](../lib/licensed/reporters).
99
+
100
+ All reporters should inherit from `Licensed::Reporters::Reporter` and override
101
+ each reporting method needed to return the appropriate data.
102
+
103
+ The following reporting points are available to give context or results from different scopes:
104
+ 1. `#report_run` - reporting on a command execution
105
+ 2. `#report_app(app)` - reporting on an application configuration
106
+ 3. `#report_source(source)` - reporting on a dependency source enumerator
107
+ 4. `#report_dependency(dependency)` - reporting on an individual dependency
108
+
109
+ Each method expects the caller to provide a block to execute for that reporting scope.
110
+ The block will be given a `report` hash object that the caller can use to provide any additional
111
+ details about the operations done in the reporting scope.
112
+
113
+ For example, the cache command lets the reporter know whether a dependency record
114
+ was cached or reused by setting a `cached` report value
115
+ ```ruby
116
+ reporter.report_dependency(dependency) do |report|
117
+ cached_record = Licensed::DependencyRecord.read(filename)
118
+ report["cached"] = force || save_dependency_record?(dependency, cached_record)
119
+ ...
120
+ end
121
+ ```
122
+
123
+ When implementing each reporting method, defining a new nested block gives flexibility
124
+ to display messages both before and after the scope execution.
125
+
126
+ For example, a reporter can show header and footer content to a source scope with
127
+ ```ruby
128
+ super do |report|
129
+ shell.info " dependencies:"
130
+ result yield report
131
+ shell.confirm " * #{report.size} dependencies"
132
+ ...
133
+ result
134
+ end
135
+ ```
136
+
137
+ Reporting methods should also return the result of the yielded block as seen above,
138
+ in order to allow transparent data returns through reporting blocks.
139
+
140
+ ### Data reports
141
+
142
+ Report hashes are nested and available to higher scopes. As an example, when a
143
+ `report_source` block has finished, the source scope's `report` hash will
144
+ contain all of the dependency reports that were obtained during the `report_source` block.
145
+
146
+ Reports are keyed by:
147
+ - `app`: `app["name"]`
148
+ - `source`: `source.class.type`
149
+ - `dependency`: `dependency.name`
150
+
151
+ When a `report_run` yielded block finishes, its `report` object will contain all app reports.
152
+ Each of those app reports in turn contain each of their source's reports, and so on.
153
+ This is particularly useful if a reporter should need to review the entire execution
154
+ of a command.
155
+
156
+ For this reason though, **reporting methods MUST be used in order**.
157
+
158
+ This is valid
159
+ ```ruby
160
+ report_run do
161
+ report_app(app) do
162
+ report_source(source) do
163
+ report_dependency(dependency) { }
164
+ end
165
+ end
166
+ end
167
+ ```
168
+
169
+ This is not valid
170
+ ```ruby
171
+ report_run do
172
+ report_dependency(dependency) { }
173
+ end
174
+ ```