licensed 3.4.3 → 3.6.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: 6ff397378a053e97414fb762f3d06c41f4217f61d9e63130aa3786456e6f2114
4
- data.tar.gz: b197f77bc54c68e5bf9462917351ca2dbda1509813315a8207fd31ed4c611de0
3
+ metadata.gz: a328b5551bdf77593f4bf97f4a846b7792898b6f749c25f5c5f39e68669f2164
4
+ data.tar.gz: ac9b2013cf25d9dab94aadd2122a41bfa2790d741bd9e1588a270cd122dfaddb
5
5
  SHA512:
6
- metadata.gz: 68d86169b07dd46f28de9cd31745e705f82e8f49e1968df5d8ff90139d6c60d2b31d861ca79d39657b5af956b3d73540cf492db6f6f84589132dc27ab65e33e5
7
- data.tar.gz: '005804bf6877d487434dc74fe9c2fbbe9c57c15bfd7924fc3a3992f7879c878056c871c4f5d7867b5e5254a59751b8839363fb4de60e1d43cdfeb6e2e1ae67f1'
6
+ metadata.gz: 846cadb01c2045ea258a785767ebfc8df3cee9d3a05648c93291c94cc21b7e84fb83146476c4afb64f9bc137a530cb84ba523ec41e2c4938396629b5b8901795
7
+ data.tar.gz: 4aa7028294894b9f0c1781b558032d80f87669e959e71aa1b635c7a8687f77b4cf11be6431f280cfcbc06ea25f605da061a9af2fb480ea134a4172f989060451
data/CHANGELOG.md CHANGED
@@ -6,6 +6,40 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 3.6.0
10
+
11
+ 2022-03-17
12
+
13
+ ### Added
14
+
15
+ - Composer dev dependencies can optionally be included in enumerated PHP dependencies (:tada: @digilist https://github.com/github/licensed/pull/486)
16
+ - Getting started usage documentation (https://github.com/github/licensed/pull/483)
17
+ - Initial support for NPM workspaces (https://github.com/github/licensed/pull/485)
18
+
19
+ ### Changed
20
+
21
+ - Transitive dependencies are now enumerated by the `pip` source (https://github.com/github/licensed/pull/480)
22
+
23
+ ### Fixed
24
+
25
+ - `licensed cache --force` will now correctly overwrite existing license classifications (https://github.com/github/licensed/pull/473)
26
+
27
+ ## 3.5.0
28
+
29
+ 2022-02-24
30
+
31
+ ### Added
32
+
33
+ - [Licensee](https://github.com/licensee/licensee) confidence thresholds can be configured in the licensed configuration file (https://github.com/github/licensed/pull/455)
34
+
35
+ ## 3.4.4
36
+
37
+ 2022-02-07
38
+
39
+ ### Fixed
40
+
41
+ - The npm and pip sources have better protection from strings causing crashes in `Hash#dig` (https://github.com/github/licensed/pull/450)
42
+
9
43
  ## 3.4.3
10
44
 
11
45
  2022-01-31
@@ -563,4 +597,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
563
597
 
564
598
  Initial release :tada:
565
599
 
566
- [Unreleased]: https://github.com/github/licensed/compare/3.4.3...HEAD
600
+ [Unreleased]: https://github.com/github/licensed/compare/3.6.0...HEAD
data/README.md CHANGED
@@ -74,6 +74,8 @@ For system wide usage, install licensed to a location on `$PATH`, e.g. `/usr/loc
74
74
 
75
75
  ## Usage
76
76
 
77
+ See [getting started](./docs/getting_started.md) for guidance using Licensed as part of your developer workflow.
78
+
77
79
  ### Available commands
78
80
 
79
81
  See the [commands documentation](./docs/commands) for documentation on available commands, or run `licensed -h` to see all of the current available commands.
@@ -86,18 +88,6 @@ A configuration file is required for most commands. See the [configuration file
86
88
 
87
89
  Licensed can enumerate dependency for many languages, package managers, and frameworks. See the [sources documentation](./docs/sources) for the list of currently available sources. Sources can be explicitly enabled and disabled as a [configuration option](./docs/configuration/dependency_source_enumerators.md.md).
88
90
 
89
- ### Automation
90
-
91
- #### Bundler
92
-
93
- The [bundler-licensed plugin](https://github.com/sergey-alekseev/bundler-licensed) runs `licensed cache` automatically when using `bundler`. See the linked repo for usage and details.
94
-
95
- #### GitHub Actions
96
-
97
- The [licensed-ci](https://github.com/marketplace/actions/licensed-ci) GitHub Action runs `licensed` as part of an opinionated CI workflow and can be configured to run on any GitHub Action event. See the linked actions for usage and details.
98
-
99
- The [setup-licensed](https://github.com/marketplace/actions/setup-github-licensed) GitHub Action installs `licensed` to the workflow environment. See the linked actions for usage and details.
100
-
101
91
  ## Development
102
92
 
103
93
  To get started after checking out the repo, run
@@ -0,0 +1,13 @@
1
+ # Customize Licensee's behavior
2
+
3
+ Licensed uses [Licensee](https://github.com/licensee/licensee) to detect and evaluate OSS licenses for project dependencies found during source enumeration. Licensed can optionally [customize Licensee's behavior](https://github.com/licensee/licensee/blob/jonabc-patch-1/docs/customizing.md#customizing-licensees-behavior) based on options set in the configuration file.
4
+
5
+ **NOTE** Matching licenses based on package manager metadata and README references is always enabled and cannot currently be configured.
6
+
7
+ ```yml
8
+ licensee:
9
+ # the confidence threshold is an integer between 1 and 100. the value represents
10
+ # the minimum percentage confidence that Licensee must have to report a matched license
11
+ # https://github.com/licensee/licensee/blob/master/docs/customizing.md#adjusting-the-confidence-threshold
12
+ confidence_threshold: 90 # default value: 98
13
+ ```
@@ -4,7 +4,7 @@ A configuration file specifies the details of enumerating and operating on licen
4
4
 
5
5
  Configuration can be specified in either YML or JSON formats, with examples given in YML. The example
6
6
  below describes common configuration values and their purposes. See [configuration options documentation](./configuration)
7
- for in depth information.
7
+ for in depth information.
8
8
 
9
9
  Additionally, some dependency sources have their own specific configuration options. See the [source documentation](./sources) for details.
10
10
 
@@ -0,0 +1,40 @@
1
+ # Getting Started
2
+
3
+ Licensed's core workflow is a multi-step process:
4
+
5
+ 1. `licensed cache` ([docs](./commands/cache.md)) is run manually and/or in an automated workflow
6
+ - Creates or updates files in a git repo containing metadata including licenses and other legal text for each dependency used by a project
7
+ 1. `licensed status` ([docs](./commands/status.md)) is run manually and/or in an automated workflow
8
+ - Validate that every detected dependency has a metadata file written in the repository, and that each dependency's stored metadata passes a number of compliance checks
9
+ 1. Any detected errors/warnings are manually [resolved](./commands/status.md#status-errors-and-resolutions)
10
+ 1. Repeat the above steps until all dependencies have metadata files stored in the repository and `licensed status` is not reporting any errors.
11
+
12
+ ## Caching dependency metadata
13
+
14
+ Caching depedency metadata into the repository brings the metadata contents closer to the dependencies where they are used, making status validation faster and possible in offline scenarios. Keeping metadata alongside your code in git gives teams an easily auditable trail for dependency updates over time, and ties into common review practices to ensure that changes aren't quietly ignored.
15
+
16
+ Caching metadata should be done whenever project code changes, to ensure that metadata files are in sync with the current state of the project code.
17
+
18
+ ## Checking dependency metadata status
19
+
20
+ Dependency metadata checks verify that every dependency
21
+
22
+ - has a metadata file available, or has been explicitly ignored by the project owners or OSS experts
23
+ - is using an approved OSS license, or has been reviewed and signed off by an OSS expert
24
+ - is up to date with the current state of a project
25
+
26
+ Checking dependencies for compliance violations should be performed whenever code changes in a repository. Moving compliance checks inline in the development workflow reduces friction later, and can even prevent costly situations later if a non-compliant dependency would need to be removed from a project.
27
+
28
+ ## Automated workflows
29
+
30
+ Integrating github/licensed into your workflow can be tedious, and luckily there are a few automated tools available to make usage easier.
31
+
32
+ ### Bundler
33
+
34
+ The [bundler-licensed plugin](https://github.com/sergey-alekseev/bundler-licensed) runs `licensed cache` automatically when using `bundler`. See the linked repo for usage and details.
35
+
36
+ ### GitHub Actions
37
+
38
+ The [licensed-ci](https://github.com/marketplace/actions/licensed-ci) GitHub Action runs `licensed` as part of an opinionated CI workflow and can be configured to run on any GitHub Action event to automatically update the cached metadata files and check their status. See the linked action for usage and details.
39
+
40
+ The [setup-licensed](https://github.com/marketplace/actions/setup-github-licensed) GitHub Action installs `licensed` to the workflow environment. See the linked actions for usage and details.
@@ -12,3 +12,12 @@ The default composer application file location is `<repository root>/composer.ph
12
12
  composer:
13
13
  application_path: "/path/to/composer"
14
14
  ```
15
+
16
+ ### Dev dependencies
17
+
18
+ By default licensed ignores all dev dependencies. To consider dev dependencies as well, use the `composer.include_dev` configuration setting.
19
+
20
+ ```yml
21
+ composer:
22
+ include_dev: true
23
+ ```
data/docs/sources/npm.md CHANGED
@@ -2,11 +2,21 @@
2
2
 
3
3
  The npm source will detect dependencies `package.json` is found at an apps `source_path`. It uses `npm list` to enumerate dependencies and metadata.
4
4
 
5
- ### Including development dependencies
5
+ ## Including development dependencies
6
6
 
7
- By default, the npm source will exclude all non-development dependencies. To include development or test dependencies, set `production_only: false` in the licensed configuration.
7
+ By default, the npm source will exclude all development dependencies. To include development or test dependencies, set `production_only: false` in the licensed configuration.
8
8
 
9
9
  ```yml
10
10
  npm:
11
11
  production_only: false
12
12
  ```
13
+
14
+ ## Using licensed with npm workspaces
15
+
16
+ Licensed requires npm version 8.5.0 or later to enumerate dependencies inside of npm workspaces. For the best results, treat each workspace directory as a separate app `source_path`:
17
+
18
+ ```yml
19
+ apps:
20
+ - source_path: path/to/workspace/a
21
+ - source_path: path/to/workspace/b
22
+ ```
data/docs/sources/pip.md CHANGED
@@ -2,11 +2,6 @@
2
2
 
3
3
  The pip source uses `pip` CLI commands to enumerate dependencies and properties. It is expected that `pip` is available in the `virtual_env_dir` specific directory before running `licensed`.
4
4
 
5
- Your repository root should also contain a `requirements.txt` file which contains all the packages and dependences that are needed. You can generate one with `pip` using the command:
6
- ```
7
- pip freeze > requirements.txt
8
- ```
9
-
10
5
  A `virtualenv` directory is required before running `licensed`. You can setup a `virtualenv` by running the command:
11
6
  ```
12
7
  virtualenv <your_venv_dir>
@@ -20,5 +15,5 @@ You have to add this setting to your licensed configuration file.
20
15
  An example usage of this might look like:
21
16
  ```yaml
22
17
  python:
23
- virtual_env_dir:"/path/to/your/venv_dir"
18
+ virtual_env_dir: "/path/to/your/venv_dir"
24
19
  ```
@@ -29,6 +29,18 @@ module Licensed
29
29
  files.clear
30
30
  end
31
31
 
32
+ # Run the command for an application configurations.
33
+ # Applies a licensee configuration for the duration of the operation.
34
+ #
35
+ # report - A Licensed::Report object for this command
36
+ #
37
+ # Returns whether the command succeeded
38
+ def run_app(app, report)
39
+ with_licensee_configuration(app, report) do
40
+ super
41
+ end
42
+ end
43
+
32
44
  # Run the command for all enumerated dependencies found in a dependency source,
33
45
  # recording results in a report.
34
46
  # Enumerating dependencies in the source is skipped if a :sources option
@@ -70,15 +82,8 @@ module Licensed
70
82
  report["filename"] = filename.to_s
71
83
  report["version"] = dependency.version
72
84
 
73
- if options[:force] || save_dependency_record?(dependency, cached_record)
74
- if dependency.record.matches?(cached_record)
75
- # use the cached license value if the license text wasn't updated
76
- dependency.record["license"] = cached_record["license"]
77
- elsif cached_record && app.reviewed?(dependency.record)
78
- # if the license text changed and the dependency is set as reviewed
79
- # force a re-review of the dependency
80
- dependency.record["review_changed_license"] = true
81
- end
85
+ if save_dependency_record?(dependency, cached_record)
86
+ update_dependency_from_cached_record(app, dependency, cached_record)
82
87
 
83
88
  dependency.record.save(filename)
84
89
  report["cached"] = true
@@ -107,6 +112,7 @@ module Licensed
107
112
  # Returns true if dependency's record should be saved
108
113
  def save_dependency_record?(dependency, cached_record)
109
114
  return true if cached_record.nil?
115
+ return true if options[:force]
110
116
 
111
117
  cached_version = cached_record["version"]
112
118
  return true if cached_version.nil? || cached_version.empty?
@@ -114,6 +120,23 @@ module Licensed
114
120
  false
115
121
  end
116
122
 
123
+ # Update dependency metadata from the cached record, to support:
124
+ # 1. continuity between cache runs to cut down on churn
125
+ # 2. notifying users when changed content needs to be reviewed
126
+ def update_dependency_from_cached_record(app, dependency, cached_record)
127
+ return if cached_record.nil?
128
+ return if options[:force]
129
+
130
+ if dependency.record.matches?(cached_record)
131
+ # use the cached license value if the license text wasn't updated
132
+ dependency.record["license"] = cached_record["license"]
133
+ elsif app.reviewed?(dependency.record)
134
+ # if the license text changed and the dependency is set as reviewed
135
+ # force a re-review of the dependency
136
+ dependency.record["review_changed_license"] = true
137
+ end
138
+ end
139
+
117
140
  # Clean up cached files that dont match current dependencies
118
141
  #
119
142
  # Returns nothing
@@ -136,6 +159,22 @@ module Licensed
136
159
  def files
137
160
  @files ||= Set.new
138
161
  end
162
+
163
+ # Configure licensee for the duration of a yielded operation
164
+ def with_licensee_configuration(app, report)
165
+ licensee_configuration = app["licensee"]
166
+ return yield unless licensee_configuration
167
+
168
+ report["licensee"] = licensee_configuration
169
+
170
+ if new_threshold = licensee_configuration["confidence_threshold"]
171
+ old_threshold, Licensee.confidence_threshold = Licensee.confidence_threshold, new_threshold
172
+ end
173
+
174
+ yield
175
+ ensure
176
+ Licensee.confidence_threshold = old_threshold if old_threshold
177
+ end
139
178
  end
140
179
  end
141
180
  end
@@ -28,7 +28,10 @@ module Licensed
28
28
  end
29
29
 
30
30
  def packages
31
- JSON.parse(File.read(composer_lock))["packages"]
31
+ packages = JSON.parse(File.read(composer_lock))
32
+ return packages["packages"] unless include_dev?
33
+
34
+ packages["packages"] + packages["packages-dev"]
32
35
  end
33
36
 
34
37
  # Returns the output from running `php composer.phar` to get package metadata
@@ -56,6 +59,11 @@ module Licensed
56
59
  def composer_lock
57
60
  config.pwd.join("composer.lock")
58
61
  end
62
+
63
+ # Returns whether to include dev packages based on the licensed configuration settings
64
+ def include_dev?
65
+ config.dig("composer", "include_dev") == true
66
+ end
59
67
  end
60
68
  end
61
69
  end
@@ -24,11 +24,13 @@ module Licensed
24
24
  end
25
25
 
26
26
  def enabled?
27
- Licensed::Shell.tool_available?("npm") && File.exist?(config.pwd.join("package.json"))
27
+ Licensed::Shell.tool_available?("npm") && File.exist?(package_json_path)
28
28
  end
29
29
 
30
30
  def enumerate_dependencies
31
31
  packages.map do |name, package|
32
+ next if package["name"] == project_name
33
+
32
34
  errors = package["problems"] unless package["path"]
33
35
  Dependency.new(
34
36
  name: name,
@@ -147,12 +149,38 @@ module Licensed
147
149
  end
148
150
 
149
151
  def peer_dependency(parent, name)
150
- parent&.dig("peerDependencies", name)
152
+ return unless parent.is_a?(Hash)
153
+
154
+ peerDependencies = parent["peerDependencies"]
155
+ # "peerDependencies" could be set to the string "[Circular]"
156
+ return unless peerDependencies.is_a?(Hash)
157
+
158
+ peerDependencies[name]
151
159
  end
152
160
 
153
161
  def extract_version(parent, name)
154
162
  parent&.dig("_dependencies", name) || peer_dependency(parent, name)
155
163
  end
164
+
165
+ # Returns the current projects name
166
+ def project_name
167
+ return unless package_json
168
+ package_json["name"]
169
+ end
170
+
171
+ ## Returns the parse package.json for the current project
172
+ def package_json
173
+ return unless File.exist?(package_json_path)
174
+
175
+ @package_json ||= JSON.parse(File.read(package_json_path))
176
+ rescue JSON::ParserError => e
177
+ message = "Licensed was unable to parse package.json. JSON Error: #{e.message}"
178
+ raise Licensed::Sources::Source::Error, message
179
+ end
180
+
181
+ def package_json_path
182
+ @package_json_path ||= File.join(config.pwd, "package.json")
183
+ end
156
184
  end
157
185
  end
158
186
  end
@@ -7,17 +7,14 @@ require "parallel"
7
7
  module Licensed
8
8
  module Sources
9
9
  class Pip < Source
10
- VERSION_OPERATORS = %w(< > <= >= == !=).freeze
11
- PACKAGE_REGEX = /^([\w\.-]+)(#{VERSION_OPERATORS.join("|")})?/
10
+ PACKAGE_INFO_SEPARATOR = "\n---\n"
12
11
 
13
12
  def enabled?
14
- return unless virtual_env_pip && Licensed::Shell.tool_available?(virtual_env_pip)
15
- File.exist?(config.pwd.join("requirements.txt"))
13
+ virtual_env_pip && Licensed::Shell.tool_available?(virtual_env_pip)
16
14
  end
17
15
 
18
16
  def enumerate_dependencies
19
- Parallel.map(packages_from_requirements_txt, in_threads: Parallel.processor_count) do |package_name|
20
- package = package_info(package_name)
17
+ packages.map do |package|
21
18
  location = File.join(package["Location"], package["Name"].gsub("-", "_") + "-" + package["Version"] + ".dist-info")
22
19
  Dependency.new(
23
20
  name: package["Name"],
@@ -34,25 +31,45 @@ module Licensed
34
31
 
35
32
  private
36
33
 
37
- def packages_from_requirements_txt
38
- File.read(config.pwd.join("requirements.txt"))
39
- .lines
40
- .reject { |line| line.include?("://") }
41
- .map { |line| line.strip.match(PACKAGE_REGEX) { |match| match.captures.first } }
42
- .compact
34
+ # Returns parsed information for all packages used by the project,
35
+ # using `pip list` to determine what packages are used and `pip show`
36
+ # to gather package information
37
+ def packages
38
+ all_packages = pip_show_command(package_names)
39
+ all_packages.split(PACKAGE_INFO_SEPARATOR).reduce([]) do |accum, val|
40
+ accum << parse_package_info(val)
41
+ end
42
+ end
43
+
44
+ # Returns the names of all of the packages used by the current project,
45
+ # as returned from `pip list`
46
+ def package_names
47
+ @package_names ||= begin
48
+ JSON.parse(pip_list_command).map { |package| package["name"] }
49
+ rescue JSON::ParserError => e
50
+ message = "Licensed was unable to parse the output from 'npm list'. JSON Error: #{e.message}"
51
+ raise Licensed::Sources::Source::Error, message
52
+ end
43
53
  end
44
54
 
45
- def package_info(package_name)
46
- p_info = pip_command(package_name).lines
47
- p_info.each_with_object(Hash.new(0)) { |pkg, a|
55
+ # Returns a hash filled with package info parsed from the email-header formatted output
56
+ # returned by `pip show`
57
+ def parse_package_info(package_info)
58
+ package_info.lines.each_with_object(Hash.new(0)) { |pkg, a|
48
59
  k, v = pkg.split(":", 2)
49
60
  next if k.nil? || k.empty?
50
61
  a[k.strip] = v&.strip
51
62
  }
52
63
  end
53
64
 
54
- def pip_command(*args)
55
- Licensed::Shell.execute(virtual_env_pip, "--disable-pip-version-check", "show", *args)
65
+ # Returns the output from `pip list --format=json`
66
+ def pip_list_command
67
+ Licensed::Shell.execute(virtual_env_pip, "--disable-pip-version-check", "list", "--format=json")
68
+ end
69
+
70
+ # Returns the output from `pip show <package> <package> ...`
71
+ def pip_show_command(packages)
72
+ Licensed::Shell.execute(virtual_env_pip, "--disable-pip-version-check", "show", *packages)
56
73
  end
57
74
 
58
75
  def virtual_env_pip
@@ -63,7 +80,10 @@ module Licensed
63
80
  def virtual_env_dir
64
81
  return @virtual_env_dir if defined?(@virtual_env_dir)
65
82
  @virtual_env_dir = begin
66
- venv_dir = config.dig("python", "virtual_env_dir")
83
+ python_config = config["python"]
84
+ return unless python_config.is_a?(Hash)
85
+
86
+ venv_dir = python_config["virtual_env_dir"]
67
87
  File.expand_path(venv_dir, config.root) if venv_dir
68
88
  end
69
89
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "3.4.3".freeze
3
+ VERSION = "3.6.0".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
data/licensed.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.required_ruby_version = ">= 2.3.0"
25
25
 
26
- spec.add_dependency "licensee", ">= 9.14.0", "< 10.0.0"
26
+ spec.add_dependency "licensee", ">= 9.15.2", "< 10.0.0"
27
27
  spec.add_dependency "thor", ">= 0.19"
28
28
  spec.add_dependency "pathname-common_prefix", "~> 0.0.1"
29
29
  spec.add_dependency "tomlrb", ">= 1.2", "< 3.0"
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: 3.4.3
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-31 00:00:00.000000000 Z
11
+ date: 2022-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 9.14.0
19
+ version: 9.15.2
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: 10.0.0
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 9.14.0
29
+ version: 9.15.2
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: 10.0.0
@@ -261,10 +261,12 @@ files:
261
261
  - docs/configuration/application_source.md
262
262
  - docs/configuration/configuration_root.md
263
263
  - docs/configuration/configuring_multiple_apps.md
264
+ - docs/configuration/customizing_licensee.md
264
265
  - docs/configuration/dependency_source_enumerators.md
265
266
  - docs/configuration/ignoring_dependencies.md
266
267
  - docs/configuration/metadata_cache.md
267
268
  - docs/configuration/reviewing_dependencies.md
269
+ - docs/getting_started.md
268
270
  - docs/migrations/v2.md
269
271
  - docs/migrations/v3.md
270
272
  - docs/packaging.md