licensed 3.5.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -1
- data/README.md +2 -12
- data/docs/configuration/customizing_licensee.md +1 -1
- data/docs/getting_started.md +40 -0
- data/docs/sources/composer.md +9 -0
- data/docs/sources/npm.md +11 -1
- data/docs/sources/pip.md +0 -5
- data/lib/licensed/commands/cache.rb +20 -9
- data/lib/licensed/sources/composer.rb +9 -1
- data/lib/licensed/sources/npm.rb +23 -1
- data/lib/licensed/sources/pip.rb +34 -17
- data/lib/licensed/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a328b5551bdf77593f4bf97f4a846b7792898b6f749c25f5c5f39e68669f2164
|
4
|
+
data.tar.gz: ac9b2013cf25d9dab94aadd2122a41bfa2790d741bd9e1588a270cd122dfaddb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 846cadb01c2045ea258a785767ebfc8df3cee9d3a05648c93291c94cc21b7e84fb83146476c4afb64f9bc137a530cb84ba523ec41e2c4938396629b5b8901795
|
7
|
+
data.tar.gz: 4aa7028294894b9f0c1781b558032d80f87669e959e71aa1b635c7a8687f77b4cf11be6431f280cfcbc06ea25f605da061a9af2fb480ea134a4172f989060451
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,24 @@ 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
|
+
|
9
27
|
## 3.5.0
|
10
28
|
|
11
29
|
2022-02-24
|
@@ -579,4 +597,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
579
597
|
|
580
598
|
Initial release :tada:
|
581
599
|
|
582
|
-
[Unreleased]: https://github.com/github/licensed/compare/3.
|
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
|
@@ -8,6 +8,6 @@ Licensed uses [Licensee](https://github.com/licensee/licensee) to detect and eva
|
|
8
8
|
licensee:
|
9
9
|
# the confidence threshold is an integer between 1 and 100. the value represents
|
10
10
|
# the minimum percentage confidence that Licensee must have to report a matched license
|
11
|
-
# https://github.com/licensee/licensee/blob/
|
11
|
+
# https://github.com/licensee/licensee/blob/master/docs/customizing.md#adjusting-the-confidence-threshold
|
12
12
|
confidence_threshold: 90 # default value: 98
|
13
13
|
```
|
@@ -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.
|
data/docs/sources/composer.md
CHANGED
@@ -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,7 +2,7 @@
|
|
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
|
-
|
5
|
+
## Including development dependencies
|
6
6
|
|
7
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
|
|
@@ -10,3 +10,13 @@ By default, the npm source will exclude all development dependencies. To include
|
|
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>
|
@@ -82,15 +82,8 @@ module Licensed
|
|
82
82
|
report["filename"] = filename.to_s
|
83
83
|
report["version"] = dependency.version
|
84
84
|
|
85
|
-
if
|
86
|
-
|
87
|
-
# use the cached license value if the license text wasn't updated
|
88
|
-
dependency.record["license"] = cached_record["license"]
|
89
|
-
elsif cached_record && app.reviewed?(dependency.record)
|
90
|
-
# if the license text changed and the dependency is set as reviewed
|
91
|
-
# force a re-review of the dependency
|
92
|
-
dependency.record["review_changed_license"] = true
|
93
|
-
end
|
85
|
+
if save_dependency_record?(dependency, cached_record)
|
86
|
+
update_dependency_from_cached_record(app, dependency, cached_record)
|
94
87
|
|
95
88
|
dependency.record.save(filename)
|
96
89
|
report["cached"] = true
|
@@ -119,6 +112,7 @@ module Licensed
|
|
119
112
|
# Returns true if dependency's record should be saved
|
120
113
|
def save_dependency_record?(dependency, cached_record)
|
121
114
|
return true if cached_record.nil?
|
115
|
+
return true if options[:force]
|
122
116
|
|
123
117
|
cached_version = cached_record["version"]
|
124
118
|
return true if cached_version.nil? || cached_version.empty?
|
@@ -126,6 +120,23 @@ module Licensed
|
|
126
120
|
false
|
127
121
|
end
|
128
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
|
+
|
129
140
|
# Clean up cached files that dont match current dependencies
|
130
141
|
#
|
131
142
|
# Returns nothing
|
@@ -28,7 +28,10 @@ module Licensed
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def packages
|
31
|
-
JSON.parse(File.read(composer_lock))
|
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
|
data/lib/licensed/sources/npm.rb
CHANGED
@@ -24,11 +24,13 @@ module Licensed
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def enabled?
|
27
|
-
Licensed::Shell.tool_available?("npm") && File.exist?(
|
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,
|
@@ -159,6 +161,26 @@ module Licensed
|
|
159
161
|
def extract_version(parent, name)
|
160
162
|
parent&.dig("_dependencies", name) || peer_dependency(parent, name)
|
161
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
|
162
184
|
end
|
163
185
|
end
|
164
186
|
end
|
data/lib/licensed/sources/pip.rb
CHANGED
@@ -7,17 +7,14 @@ require "parallel"
|
|
7
7
|
module Licensed
|
8
8
|
module Sources
|
9
9
|
class Pip < Source
|
10
|
-
|
11
|
-
PACKAGE_REGEX = /^([\w\.-]+)(#{VERSION_OPERATORS.join("|")})?/
|
10
|
+
PACKAGE_INFO_SEPARATOR = "\n---\n"
|
12
11
|
|
13
12
|
def enabled?
|
14
|
-
|
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
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
55
|
-
|
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
|
data/lib/licensed/version.rb
CHANGED
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
|
+
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-
|
11
|
+
date: 2022-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: licensee
|
@@ -266,6 +266,7 @@ files:
|
|
266
266
|
- docs/configuration/ignoring_dependencies.md
|
267
267
|
- docs/configuration/metadata_cache.md
|
268
268
|
- docs/configuration/reviewing_dependencies.md
|
269
|
+
- docs/getting_started.md
|
269
270
|
- docs/migrations/v2.md
|
270
271
|
- docs/migrations/v3.md
|
271
272
|
- docs/packaging.md
|