licensed 2.12.1 → 2.14.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +37 -43
- data/.github/workflows/test.yml +2 -2
- data/CHANGELOG.md +42 -2
- data/CONTRIBUTING.md +7 -6
- data/docs/configuration.md +1 -7
- data/docs/sources/go.md +20 -0
- data/lib/licensed/cli.rb +8 -9
- data/lib/licensed/commands/cache.rb +3 -3
- data/lib/licensed/commands/command.rb +26 -4
- data/lib/licensed/commands/environment.rb +7 -7
- data/lib/licensed/commands/list.rb +2 -2
- data/lib/licensed/commands/notices.rb +3 -3
- data/lib/licensed/commands/status.rb +2 -2
- data/lib/licensed/configuration.rb +17 -12
- data/lib/licensed/dependency_record.rb +4 -0
- data/lib/licensed/shell.rb +21 -4
- data/lib/licensed/sources/bundler.rb +4 -3
- data/lib/licensed/sources/go.rb +43 -43
- data/lib/licensed/sources/npm.rb +13 -1
- data/lib/licensed/sources/yarn.rb +14 -6
- data/lib/licensed/version.rb +1 -1
- data/licensed.gemspec +0 -1
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f91fb96a7fae9a97255650d8b27b65236f681b69dcbe3092691bb703f04b60f
|
4
|
+
data.tar.gz: '0009173e203fbec4670773120888a2389c8a8e451a8d29ac0224548d8304df01'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c463e87b87a2907a935f62c4191c754b499a2737bed527b0573030272a13b0e7daf780418602dc6a71522049dcf8e7a53b60ad46c3d24089b685b35453d4f4a
|
7
|
+
data.tar.gz: 4b33b7d301373075334f0302859ad7a4d9321a40c68df1a4f22f0af30ff73325190cdabd70532a48fd6c27bbed45532121065aeb61476a9b0bf3619f5c703924
|
@@ -1,18 +1,12 @@
|
|
1
|
-
name:
|
1
|
+
name: Build and publish release assets
|
2
2
|
|
3
|
-
on:
|
3
|
+
on:
|
4
|
+
release:
|
5
|
+
types: [created]
|
4
6
|
|
5
7
|
jobs:
|
6
|
-
tag_filter:
|
7
|
-
runs-on: ubuntu-latest
|
8
|
-
if: startsWith(github.ref, 'refs/tags/')
|
9
|
-
steps:
|
10
|
-
- run: exit 0
|
11
|
-
|
12
8
|
package_linux:
|
13
9
|
runs-on: ubuntu-latest
|
14
|
-
needs: tag_filter
|
15
|
-
|
16
10
|
steps:
|
17
11
|
- uses: actions/checkout@v2
|
18
12
|
- name: Set up Ruby 2.6
|
@@ -23,17 +17,15 @@ jobs:
|
|
23
17
|
- name: Build package
|
24
18
|
run: script/packages/linux
|
25
19
|
env:
|
26
|
-
VERSION: ${{github.event.
|
20
|
+
VERSION: ${{github.event.release.tag_name}}
|
27
21
|
|
28
22
|
- uses: actions/upload-artifact@v2
|
29
23
|
with:
|
30
|
-
name: ${{github.event.
|
31
|
-
path: pkg/${{github.event.
|
24
|
+
name: ${{github.event.release.tag_name}}-linux
|
25
|
+
path: pkg/${{github.event.release.tag_name}}/licensed-${{github.event.release.tag_name}}-linux-x64.tar.gz
|
32
26
|
|
33
27
|
package_mac:
|
34
28
|
runs-on: macOS-latest
|
35
|
-
needs: tag_filter
|
36
|
-
|
37
29
|
steps:
|
38
30
|
- uses: actions/checkout@v2
|
39
31
|
- name: Set up Ruby 2.6
|
@@ -44,17 +36,15 @@ jobs:
|
|
44
36
|
- name: Build package
|
45
37
|
run: script/packages/mac
|
46
38
|
env:
|
47
|
-
VERSION: ${{github.event.
|
39
|
+
VERSION: ${{github.event.release.tag_name}}
|
48
40
|
|
49
41
|
- uses: actions/upload-artifact@v2
|
50
42
|
with:
|
51
|
-
name: ${{github.event.
|
52
|
-
path: pkg/${{github.event.
|
43
|
+
name: ${{github.event.release.tag_name}}-darwin
|
44
|
+
path: pkg/${{github.event.release.tag_name}}/licensed-${{github.event.release.tag_name}}-darwin-x64.tar.gz
|
53
45
|
|
54
46
|
build_gem:
|
55
47
|
runs-on: ubuntu-latest
|
56
|
-
needs: tag_filter
|
57
|
-
|
58
48
|
steps:
|
59
49
|
- uses: actions/checkout@v2
|
60
50
|
- name: Set up Ruby 2.6
|
@@ -63,25 +53,16 @@ jobs:
|
|
63
53
|
ruby-version: 2.6.x
|
64
54
|
|
65
55
|
- name: Build gem
|
66
|
-
run: gem build
|
56
|
+
run: gem build licensed.gemspec -o licensed-${{github.event.release.tag_name}}.gem
|
67
57
|
|
68
58
|
- uses: actions/upload-artifact@v2
|
69
59
|
with:
|
70
|
-
name: ${{github.event.
|
71
|
-
path: licensed-${{github.event.
|
72
|
-
|
73
|
-
create_release:
|
74
|
-
runs-on: ubuntu-latest
|
75
|
-
needs: [package_linux, package_mac, build_gem]
|
76
|
-
steps:
|
77
|
-
- uses: Roang-zero1/github-create-release-action@v1.0.2
|
78
|
-
env:
|
79
|
-
GITHUB_TOKEN: ${{ secrets.API_AUTH_TOKEN }}
|
80
|
-
VERSION_REGEX: "^[[:digit:]]+\\.[[:digit:]]+\\.[[:digit:]]+"
|
60
|
+
name: ${{github.event.release.tag_name}}-gem
|
61
|
+
path: licensed-${{github.event.release.tag_name}}.gem
|
81
62
|
|
82
63
|
upload_packages:
|
83
64
|
runs-on: ubuntu-latest
|
84
|
-
needs: [
|
65
|
+
needs: [package_linux, package_mac, build_gem]
|
85
66
|
|
86
67
|
steps:
|
87
68
|
- name: Set up Ruby 2.6
|
@@ -92,32 +73,45 @@ jobs:
|
|
92
73
|
- name: Download linux package
|
93
74
|
uses: actions/download-artifact@v2
|
94
75
|
with:
|
95
|
-
name: ${{github.event.
|
76
|
+
name: ${{github.event.release.tag_name}}-linux
|
96
77
|
|
97
78
|
- name: Download macOS package
|
98
79
|
uses: actions/download-artifact@v2
|
99
80
|
with:
|
100
|
-
name: ${{github.event.
|
81
|
+
name: ${{github.event.release.tag_name}}-darwin
|
101
82
|
|
102
83
|
- name: Download gem
|
103
84
|
uses: actions/download-artifact@v2
|
104
85
|
with:
|
105
|
-
name: ${{github.event.
|
86
|
+
name: ${{github.event.release.tag_name}}-gem
|
106
87
|
|
107
|
-
- name: Publish
|
108
|
-
uses:
|
88
|
+
- name: Publish linux package
|
89
|
+
uses: actions/upload-release-asset@v1
|
90
|
+
env:
|
91
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
109
92
|
with:
|
110
|
-
|
93
|
+
upload_url: ${{ github.event.release.upload_url }}
|
94
|
+
asset_path: ./licensed-${{github.event.release.tag_name}}-linux-x64.tar.gz
|
95
|
+
asset_name: licensed-${{github.event.release.tag_name}}-linux-x64.tar.gz
|
96
|
+
asset_content_type: application/gzip
|
97
|
+
|
98
|
+
- name: Publish mac package
|
99
|
+
uses: actions/upload-release-asset@v1
|
111
100
|
env:
|
112
|
-
GITHUB_TOKEN: ${{secrets.
|
101
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
102
|
+
with:
|
103
|
+
upload_url: ${{ github.event.release.upload_url }}
|
104
|
+
asset_path: ./licensed-${{github.event.release.tag_name}}-darwin-x64.tar.gz
|
105
|
+
asset_name: licensed-${{github.event.release.tag_name}}-darwin-x64.tar.gz
|
106
|
+
asset_content_type: application/gzip
|
113
107
|
|
114
108
|
- name: Publish gem to RubyGems
|
115
109
|
run: |
|
116
110
|
mkdir -p $HOME/.gem
|
117
111
|
touch $HOME/.gem/credentials
|
118
112
|
chmod 0600 $HOME/.gem/credentials
|
119
|
-
printf -- "---\n:rubygems_api_key: ${
|
113
|
+
printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_KEY}\n" > $HOME/.gem/credentials
|
120
114
|
gem push $GEM
|
121
115
|
env:
|
122
|
-
|
123
|
-
GEM: licensed-${{github.event.
|
116
|
+
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
117
|
+
GEM: licensed-${{github.event.release.tag_name}}.gem
|
data/.github/workflows/test.yml
CHANGED
@@ -116,7 +116,7 @@ jobs:
|
|
116
116
|
runs-on: ubuntu-latest
|
117
117
|
strategy:
|
118
118
|
matrix:
|
119
|
-
ruby: [ 2.4.x, 2.5.x, 2.6.x ]
|
119
|
+
ruby: [ 2.4.x, 2.5.x, 2.6.x, 2.7.x ]
|
120
120
|
steps:
|
121
121
|
- uses: actions/checkout@v2
|
122
122
|
- name: Set up Ruby
|
@@ -165,7 +165,7 @@ jobs:
|
|
165
165
|
runs-on: ubuntu-latest
|
166
166
|
strategy:
|
167
167
|
matrix:
|
168
|
-
go: [ '1.
|
168
|
+
go: [ '1.10.x', '1.11.x', '1.12.x', '1.13.x', '1.14.x', '1.15.x' ]
|
169
169
|
steps:
|
170
170
|
- uses: actions/checkout@v2
|
171
171
|
- name: Setup go
|
data/CHANGELOG.md
CHANGED
@@ -6,11 +6,51 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## 2.14.2
|
10
|
+
2020-11-20
|
11
|
+
|
12
|
+
## Fixed
|
13
|
+
- Yarn source correctly finds dependency paths on disk (https://github.com/github/licensed/pull/326)
|
14
|
+
- Go source better handles finding dependencies that have been vendored (https://github.com/github/licensed/pull/323)
|
15
|
+
|
16
|
+
## 2.14.1
|
17
|
+
2020-10-09
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- Shell command output is encoded to UTF8 (https://github.com/github/licensed/pull/319)
|
21
|
+
|
22
|
+
## 2.14.0
|
23
|
+
2020-10-04
|
24
|
+
|
25
|
+
### Added
|
26
|
+
- `reviewed` dependencies can use glob pattern matching (https://github.com/github/licensed/pull/313)
|
27
|
+
|
28
|
+
### Fixed
|
29
|
+
- Fix configuring source path globs that expand into a single directory (https://github.com/github/licensed/pull/312)
|
30
|
+
|
31
|
+
## 2.13.0
|
32
|
+
2020-09-23
|
33
|
+
|
34
|
+
### Added
|
35
|
+
- `status` command results can be output in YAML and JSON formats (:tada: @julianvilas https://github.com/github/licensed/pull/303)
|
36
|
+
|
37
|
+
### Fixed
|
38
|
+
- `licensed` no longer crashes when parsing invalid YAML from cached records (https://github.com/github/licensed/pull/306)
|
39
|
+
- NPM source will no longer crash when invalid JSON is returned from npm CLI calls (https://github.com/github/licensed/pull/300)
|
40
|
+
- Bundler source is fixed to work properly with `gems.rb` lockfiles (https://github.com/github/licensed/pull/299)
|
41
|
+
|
42
|
+
## 2.12.2
|
43
|
+
2020-07-07
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
- Cleaned up ruby 2.7 warnings (:tada: @jurre https://github.com/github/licensed/pull/292)
|
47
|
+
- Cleaned up additional warnings in tests (https://github.com/github/licensed/pull/293)
|
48
|
+
|
9
49
|
## 2.12.1
|
10
50
|
2020-06-30
|
11
51
|
|
12
52
|
### Fixed
|
13
|
-
- `licensed` no longer exits an error code when using the `--sources` CLI argument(https://github.com/github/licensed/pull/290)
|
53
|
+
- `licensed` no longer exits an error code when using the `--sources` CLI argument (https://github.com/github/licensed/pull/290)
|
14
54
|
|
15
55
|
## 2.12.0
|
16
56
|
2020-06-19
|
@@ -333,4 +373,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
333
373
|
|
334
374
|
Initial release :tada:
|
335
375
|
|
336
|
-
[Unreleased]: https://github.com/github/licensed/compare/2.
|
376
|
+
[Unreleased]: https://github.com/github/licensed/compare/2.14.2...HEAD
|
data/CONTRIBUTING.md
CHANGED
@@ -39,7 +39,7 @@ Pull requests that include a new dependency source must also
|
|
39
39
|
## Releasing
|
40
40
|
If you are the current maintainer of this gem:
|
41
41
|
|
42
|
-
1. Create a branch for the release: git checkout -b cut-release-
|
42
|
+
1. Create a branch for the release: git checkout -b cut-release-xx.xx.xx
|
43
43
|
2. Make sure your local dependencies are up to date: `script/bootstrap`
|
44
44
|
3. Ensure that tests are green: `bundle exec rake test`
|
45
45
|
4. Bump gem version in lib/licensed/version.rb.
|
@@ -51,15 +51,16 @@ If you are the current maintainer of this gem:
|
|
51
51
|
2. Install the new gem locally
|
52
52
|
3. Test behavior locally, branch deploy, whatever needs to happen
|
53
53
|
9. Merge github/licensed PR
|
54
|
-
10.
|
54
|
+
10. Create a new [github/licensed release](https://github.com/github/licensed/releases)
|
55
|
+
- Set the release name and tag to the release version - `x.xx.x`
|
56
|
+
- Set the release body to the changelog entries for the release
|
55
57
|
|
56
58
|
The following steps will happen automatically from a GitHub Actions workflow
|
57
|
-
after
|
59
|
+
after creating the release. In case that fails, the following steps can be performed manually
|
58
60
|
|
59
|
-
11. Push to rubygems.org -- `gem push licensed-x.xx.xx.gem`
|
61
|
+
11. Push the gem from (7) to rubygems.org -- `gem push licensed-x.xx.xx.gem`
|
60
62
|
12. Build packages for new tag: `VERSION=x.xx.xx bundle exec rake package`
|
61
|
-
13.
|
62
|
-
14. Add built packages to new release
|
63
|
+
13. Upload packages from (12) to release from (10)
|
63
64
|
|
64
65
|
## Resources
|
65
66
|
|
data/docs/configuration.md
CHANGED
@@ -23,7 +23,7 @@ If a root path is not specified, it will default to using the following, in orde
|
|
23
23
|
|
24
24
|
The `source_path` property can use a glob path to share configuration properties across multiple application entrypoints.
|
25
25
|
|
26
|
-
For example, there is a common pattern in
|
26
|
+
For example, there is a common pattern in Go projects to include multiple executable entrypoints under folders in `cmd`. Using a glob pattern allows users to avoid manually configuring and maintaining multiple licensed application `source_path`s. Using a glob pattern will also ensure that any new entrypoints matching the pattern are automatically picked up by licensed commands as they are added.
|
27
27
|
|
28
28
|
```yml
|
29
29
|
sources:
|
@@ -118,12 +118,6 @@ ignored:
|
|
118
118
|
bower:
|
119
119
|
- some-internal-package
|
120
120
|
|
121
|
-
go:
|
122
|
-
# ignore all go packages from import paths starting with github.com/internal-package
|
123
|
-
# see the `File.fnmatch?` documentation for details on how patterns are matched.
|
124
|
-
# comparisons use the FNM_CASEFOLD and FNM_PATHNAME flags
|
125
|
-
- github.com/internal-package/**/*
|
126
|
-
|
127
121
|
# These dependencies have licenses not on the `allowed` list and have been reviewed.
|
128
122
|
# They will be cached and checked, but will not raise errors or warnings for a
|
129
123
|
# non-allowed license. Dependencies on this list will still raise errors if
|
data/docs/sources/go.md
CHANGED
@@ -24,6 +24,26 @@ The setting supports absolute, relative and expandable (e.g. "~") paths. Relati
|
|
24
24
|
|
25
25
|
Non-empty `GOPATH` configuration settings will override the `GOPATH` environment variable while enumerating `go` dependencies. The `GOPATH` environment variable is restored once dependencies have been enumerated.
|
26
26
|
|
27
|
+
#### Reviewing and ignoring all packages from a Go module
|
28
|
+
|
29
|
+
Go's package and module structure has common conventions that documentation and metadata for all packages in a module live in the module root. In this scenario all packages share the same LICENSE information and can be reviewed or ignored at the module level rather than per-package using glob patterns.
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
reviewed:
|
33
|
+
go:
|
34
|
+
# review all Go packages from import paths starting with github.com/external-package
|
35
|
+
# see the `File.fnmatch?` documentation for details on how patterns are matched.
|
36
|
+
# comparisons use the FNM_CASEFOLD and FNM_PATHNAME flags
|
37
|
+
- github.com/external-package/**/*
|
38
|
+
|
39
|
+
ignored:
|
40
|
+
go:
|
41
|
+
# ignore all Go packages from import paths starting with github.com/internal-package
|
42
|
+
# see the `File.fnmatch?` documentation for details on how patterns are matched.
|
43
|
+
# comparisons use the FNM_CASEFOLD and FNM_PATHNAME flags
|
44
|
+
- github.com/internal-package/**/*
|
45
|
+
```
|
46
|
+
|
27
47
|
#### Versioning
|
28
48
|
|
29
49
|
The go source supports multiple versioning strategies to determine if cached dependency metadata is stale. A version strategy is chosen based on the availability of go module information along with the current app configuration.
|
data/lib/licensed/cli.rb
CHANGED
@@ -14,17 +14,18 @@ module Licensed
|
|
14
14
|
desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
|
15
15
|
def cache
|
16
16
|
run Licensed::Commands::Cache.new(config: config),
|
17
|
-
|
17
|
+
force: options[:force], sources: options[:sources]
|
18
18
|
end
|
19
19
|
|
20
20
|
desc "status", "Check status of dependencies' cached licenses"
|
21
|
+
method_option :format, enum: ["yaml", "json"],
|
22
|
+
desc: "Output format"
|
21
23
|
method_option :config, aliases: "-c", type: :string,
|
22
24
|
desc: "Path to licensed configuration file"
|
23
25
|
method_option :sources, aliases: "-s", type: :array,
|
24
26
|
desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
|
25
27
|
def status
|
26
|
-
run Licensed::Commands::Status.new(config: config),
|
27
|
-
{ sources: options[:sources] }
|
28
|
+
run Licensed::Commands::Status.new(config: config), sources: options[:sources], reporter: options[:format]
|
28
29
|
end
|
29
30
|
|
30
31
|
desc "list", "List dependencies"
|
@@ -33,8 +34,7 @@ module Licensed
|
|
33
34
|
method_option :sources, aliases: "-s", type: :array,
|
34
35
|
desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
|
35
36
|
def list
|
36
|
-
run Licensed::Commands::List.new(config: config),
|
37
|
-
{ sources: options[:sources] }
|
37
|
+
run Licensed::Commands::List.new(config: config), sources: options[:sources]
|
38
38
|
end
|
39
39
|
|
40
40
|
desc "notices", "Generate a NOTICE file from cached records"
|
@@ -43,8 +43,7 @@ module Licensed
|
|
43
43
|
method_option :sources, aliases: "-s", type: :array,
|
44
44
|
desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
|
45
45
|
def notices
|
46
|
-
run Licensed::Commands::Notices.new(config: config),
|
47
|
-
{ sources: options[:sources] }
|
46
|
+
run Licensed::Commands::Notices.new(config: config), sources: options[:sources]
|
48
47
|
end
|
49
48
|
|
50
49
|
map "-v" => :version
|
@@ -60,7 +59,7 @@ module Licensed
|
|
60
59
|
method_option :config, aliases: "-c", type: :string,
|
61
60
|
desc: "Path to licensed configuration file"
|
62
61
|
def env
|
63
|
-
run Licensed::Commands::Environment.new(config: config),
|
62
|
+
run Licensed::Commands::Environment.new(config: config), reporter: options[:format]
|
64
63
|
end
|
65
64
|
|
66
65
|
desc "migrate", "Migrate from a previous version of licensed"
|
@@ -99,7 +98,7 @@ module Licensed
|
|
99
98
|
end
|
100
99
|
|
101
100
|
def run(command, **args)
|
102
|
-
exit command.run(args)
|
101
|
+
exit command.run(**args)
|
103
102
|
end
|
104
103
|
end
|
105
104
|
end
|
@@ -2,12 +2,12 @@
|
|
2
2
|
module Licensed
|
3
3
|
module Commands
|
4
4
|
class Cache < Command
|
5
|
-
#
|
5
|
+
# Returns the default reporter to use during the command run
|
6
6
|
#
|
7
7
|
# options - The options the command was run with
|
8
8
|
#
|
9
|
-
#
|
10
|
-
def
|
9
|
+
# Returns a Licensed::Reporters::CacheReporter
|
10
|
+
def default_reporter(options)
|
11
11
|
Licensed::Reporters::CacheReporter.new
|
12
12
|
end
|
13
13
|
|
@@ -37,13 +37,29 @@ module Licensed
|
|
37
37
|
result
|
38
38
|
end
|
39
39
|
|
40
|
-
#
|
40
|
+
# Creates a reporter to use during a command run
|
41
41
|
#
|
42
42
|
# options - The options the command was run with
|
43
43
|
#
|
44
|
-
#
|
44
|
+
# Returns the reporter to use during the command run
|
45
45
|
def create_reporter(options)
|
46
|
-
|
46
|
+
return options[:reporter] if options[:reporter].is_a?(Licensed::Reporters::Reporter)
|
47
|
+
|
48
|
+
if options[:reporter].is_a?(String)
|
49
|
+
klass = "#{options[:reporter].capitalize}Reporter"
|
50
|
+
return Licensed::Reporters.const_get(klass).new if Licensed::Reporters.const_defined?(klass)
|
51
|
+
end
|
52
|
+
|
53
|
+
default_reporter(options)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the default reporter to use during the command run
|
57
|
+
#
|
58
|
+
# options - The options the command was run with
|
59
|
+
#
|
60
|
+
# Raises an error
|
61
|
+
def default_reporter(options)
|
62
|
+
raise "`default_reporter` must be implemented by commands"
|
47
63
|
end
|
48
64
|
|
49
65
|
protected
|
@@ -56,6 +72,12 @@ module Licensed
|
|
56
72
|
# Returns whether the command succeeded for the application.
|
57
73
|
def run_app(app)
|
58
74
|
reporter.report_app(app) do |report|
|
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
|
80
|
+
|
59
81
|
Dir.chdir app.source_path do
|
60
82
|
begin
|
61
83
|
# allow additional report data to be given by commands
|
@@ -125,7 +147,7 @@ module Licensed
|
|
125
147
|
end
|
126
148
|
|
127
149
|
evaluate_dependency(app, source, dependency, report)
|
128
|
-
rescue Licensed::Shell::Error => err
|
150
|
+
rescue Licensed::DependencyRecord::Error, Licensed::Shell::Error => err
|
129
151
|
report.errors << err.message
|
130
152
|
false
|
131
153
|
end
|
@@ -35,13 +35,13 @@ module Licensed
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
# Returns the default reporter to use during the command run
|
39
|
+
#
|
40
|
+
# options - The options the command was run with
|
41
|
+
#
|
42
|
+
# Returns a Licensed::Reporters::StatusReporter
|
43
|
+
def default_reporter(options)
|
44
|
+
Licensed::Reporters::YamlReporter.new
|
45
45
|
end
|
46
46
|
|
47
47
|
protected
|
@@ -2,12 +2,12 @@
|
|
2
2
|
module Licensed
|
3
3
|
module Commands
|
4
4
|
class List < Command
|
5
|
-
#
|
5
|
+
# Returns the default reporter to use during the command run
|
6
6
|
#
|
7
7
|
# options - The options the command was run with
|
8
8
|
#
|
9
9
|
# Returns a Licensed::Reporters::ListReporter
|
10
|
-
def
|
10
|
+
def default_reporter(options)
|
11
11
|
Licensed::Reporters::ListReporter.new
|
12
12
|
end
|
13
13
|
|
@@ -2,12 +2,12 @@
|
|
2
2
|
module Licensed
|
3
3
|
module Commands
|
4
4
|
class Notices < Command
|
5
|
-
#
|
5
|
+
# Returns the default reporter to use during the command run
|
6
6
|
#
|
7
7
|
# options - The options the command was run with
|
8
8
|
#
|
9
|
-
#
|
10
|
-
def
|
9
|
+
# Returns a Licensed::Reporters::CacheReporter
|
10
|
+
def default_reporter(options)
|
11
11
|
Licensed::Reporters::NoticesReporter.new
|
12
12
|
end
|
13
13
|
|
@@ -4,12 +4,12 @@ require "yaml"
|
|
4
4
|
module Licensed
|
5
5
|
module Commands
|
6
6
|
class Status < Command
|
7
|
-
#
|
7
|
+
# Returns the default reporter to use during the command run
|
8
8
|
#
|
9
9
|
# options - The options the command was run with
|
10
10
|
#
|
11
11
|
# Returns a Licensed::Reporters::StatusReporter
|
12
|
-
def
|
12
|
+
def default_reporter(options)
|
13
13
|
Licensed::Reporters::StatusReporter.new
|
14
14
|
end
|
15
15
|
|
@@ -69,7 +69,9 @@ module Licensed
|
|
69
69
|
|
70
70
|
# Is the given dependency reviewed?
|
71
71
|
def reviewed?(dependency)
|
72
|
-
Array(self["reviewed"][dependency["type"]]).
|
72
|
+
Array(self["reviewed"][dependency["type"]]).any? do |pattern|
|
73
|
+
File.fnmatch?(pattern, dependency["name"], File::FNM_PATHNAME | File::FNM_CASEFOLD)
|
74
|
+
end
|
73
75
|
end
|
74
76
|
|
75
77
|
# Is the given dependency ignored?
|
@@ -158,19 +160,22 @@ module Licensed
|
|
158
160
|
def self.expand_app_source_path(app_config)
|
159
161
|
return app_config if app_config["source_path"].to_s.empty?
|
160
162
|
|
163
|
+
# check if the source path maps to an existing directory
|
161
164
|
source_path = File.expand_path(app_config["source_path"], AppConfiguration.root_for(app_config))
|
165
|
+
return app_config if Dir.exist?(source_path)
|
166
|
+
|
167
|
+
# try to expand the source path for glob patterns
|
162
168
|
expanded_source_paths = Dir.glob(source_path).select { |p| File.directory?(p) }
|
163
|
-
|
164
|
-
return app_config if expanded_source_paths.size <= 1
|
169
|
+
configs = expanded_source_paths.map { |path| app_config.merge("source_path" => path) }
|
165
170
|
|
166
|
-
#
|
167
|
-
|
168
|
-
config = app_config.merge("source_path" => path)
|
171
|
+
# if no directories are found for the source path, return the original config
|
172
|
+
return app_config if configs.size == 0
|
169
173
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
+
# update configured values for name and cache_path for uniqueness.
|
175
|
+
# this is only needed when values are explicitly set, AppConfiguration
|
176
|
+
# will handle configurations that don't have these explicitly set
|
177
|
+
configs.each do |config|
|
178
|
+
dir_name = File.basename(config["source_path"])
|
174
179
|
config["name"] = "#{config["name"]}-#{dir_name}" if config["name"]
|
175
180
|
|
176
181
|
# if a cache_path is set and is not marked as shared, append the app name
|
@@ -178,9 +183,9 @@ module Licensed
|
|
178
183
|
if config["cache_path"] && config["shared_cache"] != true
|
179
184
|
config["cache_path"] = File.join(config["cache_path"], dir_name)
|
180
185
|
end
|
181
|
-
|
182
|
-
config
|
183
186
|
end
|
187
|
+
|
188
|
+
configs
|
184
189
|
end
|
185
190
|
|
186
191
|
# Find a default configuration file in the given directory.
|
@@ -5,6 +5,8 @@ require "licensee"
|
|
5
5
|
|
6
6
|
module Licensed
|
7
7
|
class DependencyRecord
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
8
10
|
class License
|
9
11
|
attr_reader :text, :sources
|
10
12
|
def initialize(content)
|
@@ -46,6 +48,8 @@ module Licensed
|
|
46
48
|
notices: data.delete("notices"),
|
47
49
|
metadata: data
|
48
50
|
)
|
51
|
+
rescue Psych::SyntaxError => e
|
52
|
+
raise Licensed::DependencyRecord::Error.new(e.message)
|
49
53
|
end
|
50
54
|
|
51
55
|
def_delegators :@metadata, :[], :[]=
|
data/lib/licensed/shell.rb
CHANGED
@@ -9,11 +9,12 @@ module Licensed
|
|
9
9
|
def self.execute(cmd, *args, allow_failure: false, env: {})
|
10
10
|
stdout, stderr, status = Open3.capture3(env, cmd, *args)
|
11
11
|
|
12
|
-
if status.success?
|
13
|
-
|
14
|
-
else
|
15
|
-
raise Error.new([cmd, *args], status.exitstatus, stderr)
|
12
|
+
if !status.success? && !allow_failure
|
13
|
+
raise Error.new([cmd, *args], status.exitstatus, encode_content(stderr))
|
16
14
|
end
|
15
|
+
|
16
|
+
# ensure that returned data is properly encoded
|
17
|
+
encode_content(stdout.strip)
|
17
18
|
end
|
18
19
|
|
19
20
|
# Executes a command and returns a boolean value indicating if the command
|
@@ -55,5 +56,21 @@ module Licensed
|
|
55
56
|
end.join(" ")
|
56
57
|
end
|
57
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
ENCODING = Encoding::UTF_8
|
63
|
+
ENCODING_OPTIONS = {
|
64
|
+
invalid: :replace,
|
65
|
+
undef: :replace,
|
66
|
+
replace: "",
|
67
|
+
univeral_newline: true
|
68
|
+
}.freeze
|
69
|
+
|
70
|
+
# Ensure that content that is returned from shell commands is in a usable
|
71
|
+
# encoding for the rest of the application
|
72
|
+
def self.encode_content(content)
|
73
|
+
content.encode(ENCODING, **ENCODING_OPTIONS)
|
74
|
+
end
|
58
75
|
end
|
59
76
|
end
|
@@ -74,7 +74,7 @@ module Licensed
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
GEMFILES =
|
77
|
+
GEMFILES = { "Gemfile" => "Gemfile.lock", "gems.rb" => "gems.locked" }
|
78
78
|
DEFAULT_WITHOUT_GROUPS = %i{development test}
|
79
79
|
|
80
80
|
def enabled?
|
@@ -272,14 +272,15 @@ module Licensed
|
|
272
272
|
|
273
273
|
# Returns the path to the Bundler Gemfile
|
274
274
|
def gemfile_path
|
275
|
-
@gemfile_path ||= GEMFILES.
|
275
|
+
@gemfile_path ||= GEMFILES.keys
|
276
|
+
.map { |g| config.pwd.join g }
|
276
277
|
.find { |f| f.exist? }
|
277
278
|
end
|
278
279
|
|
279
280
|
# Returns the path to the Bundler Gemfile.lock
|
280
281
|
def lockfile_path
|
281
282
|
return unless gemfile_path
|
282
|
-
@lockfile_path ||= gemfile_path.dirname.join(
|
283
|
+
@lockfile_path ||= gemfile_path.dirname.join(GEMFILES[gemfile_path.basename.to_s])
|
283
284
|
end
|
284
285
|
|
285
286
|
# Returns the configured bundler executable to use, or "bundle" by default.
|
data/lib/licensed/sources/go.rb
CHANGED
@@ -15,8 +15,7 @@ module Licensed
|
|
15
15
|
def enumerate_dependencies
|
16
16
|
with_configured_gopath do
|
17
17
|
packages.map do |package|
|
18
|
-
import_path =
|
19
|
-
import_path ||= package["ImportPath"]
|
18
|
+
import_path = non_vendored_import_path(package)
|
20
19
|
error = package.dig("Error", "Err") if package["Error"]
|
21
20
|
|
22
21
|
Dependency.new(
|
@@ -81,34 +80,26 @@ module Licensed
|
|
81
80
|
# return true if package self-identifies
|
82
81
|
return true if package["Standard"]
|
83
82
|
|
84
|
-
import_path = package
|
83
|
+
import_path = non_vendored_import_path(package)
|
85
84
|
return false unless import_path
|
86
85
|
|
87
|
-
#
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# return true if any of the go standard packages matches against
|
98
|
-
# the non-vendored import path
|
99
|
-
return true if go_std_packages.include?(non_vendored_import_path)
|
100
|
-
return true if go_std_packages.include?(non_vendored_import_path.sub("golang.org", "internal"))
|
101
|
-
|
102
|
-
# modify the import path to look like the import path `go list` returns for vendored std packages
|
103
|
-
vendor_path = import_path.sub("#{root_package["ImportPath"]}/", "")
|
104
|
-
go_std_packages.include?(vendor_path) || go_std_packages.include?(vendor_path.sub("golang.org", "golang_org"))
|
86
|
+
# check different variations of the import path to match against
|
87
|
+
# what's returned from `go list std`
|
88
|
+
[
|
89
|
+
import_path,
|
90
|
+
import_path.sub("golang.org", "internal"),
|
91
|
+
import_path.sub("golang.org", "golang_org"),
|
92
|
+
].any? do |path|
|
93
|
+
# true if go standard packages includes the path or "vendor/<path>"
|
94
|
+
go_std_packages.include?(path) || go_std_packages.include?("vendor/#{path}")
|
95
|
+
end
|
105
96
|
end
|
106
97
|
|
107
98
|
# Returns whether the package is local to the current project
|
108
99
|
def local_package?(package)
|
109
|
-
return false unless package && package["
|
110
|
-
|
111
|
-
|
100
|
+
return false unless package && package["Dir"]
|
101
|
+
return false unless File.fnmatch?("#{config.root.to_s}*", package["Dir"])
|
102
|
+
vendored_path_parts(package).nil?
|
112
103
|
end
|
113
104
|
|
114
105
|
# Returns the version for a given package
|
@@ -155,36 +146,45 @@ module Licensed
|
|
155
146
|
|
156
147
|
# search root choices:
|
157
148
|
# 1. module directory if using go modules and directory is available
|
158
|
-
# 2. vendor folder if package is vendored
|
159
|
-
# 3. package root value if available
|
160
|
-
# 4. GOPATH if the package directory is under the gopath
|
161
|
-
# 5. nil
|
162
149
|
module_dir = package.dig("Module", "Dir")
|
163
150
|
return module_dir if module_dir
|
164
|
-
|
151
|
+
|
152
|
+
# 2. vendor folder if package is vendored
|
153
|
+
parts = vendored_path_parts(package)
|
154
|
+
return parts[:vendor_path] if parts
|
155
|
+
|
156
|
+
# 3. package root value if available
|
165
157
|
return package["Root"] if package["Root"]
|
158
|
+
|
159
|
+
# 4. GOPATH if the package directory is under the gopath
|
166
160
|
return gopath if package["Dir"]&.start_with?(gopath)
|
161
|
+
|
162
|
+
# 5. nil
|
167
163
|
nil
|
168
164
|
end
|
169
165
|
|
170
|
-
#
|
171
|
-
#
|
166
|
+
# If the package is vendored, returns a Match object containing named
|
167
|
+
# :vendor_path and :import_path match groups based on the packages "Dir" value
|
168
|
+
#
|
169
|
+
# If the package is not vendored, returns nil
|
172
170
|
#
|
173
|
-
#
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
path.start_with?(base.to_s) && path.include?("vendor/")
|
171
|
+
# package - Package to get vendored path information for
|
172
|
+
def vendored_path_parts(package)
|
173
|
+
return if package.nil? || package["Dir"].nil?
|
174
|
+
package["Dir"].match(/^(?<vendor_path>#{config.root}(\/.+)*\/[^\/]*vendor[^\/]*)\/(?<import_path>.+)$/i)
|
178
175
|
end
|
179
176
|
|
180
|
-
# Returns the
|
177
|
+
# Returns the non-vendored portion of the package import path if vendored,
|
178
|
+
# otherwise returns the package's import path as given
|
181
179
|
#
|
182
|
-
#
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
return
|
187
|
-
|
180
|
+
# package - Package to get the non-vendored import path for
|
181
|
+
def non_vendored_import_path(package)
|
182
|
+
return if package.nil?
|
183
|
+
parts = vendored_path_parts(package)
|
184
|
+
return parts[:import_path] if parts
|
185
|
+
|
186
|
+
# if a package isn't vendored, return the packages "ImportPath"
|
187
|
+
package["ImportPath"]
|
188
188
|
end
|
189
189
|
|
190
190
|
# Returns a hash of information about the package with a given import path
|
data/lib/licensed/sources/npm.rb
CHANGED
@@ -30,7 +30,7 @@ module Licensed
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def packages
|
33
|
-
root_dependencies =
|
33
|
+
root_dependencies = package_metadata["dependencies"]
|
34
34
|
recursive_dependencies(root_dependencies).each_with_object({}) do |(name, results), hsh|
|
35
35
|
results.uniq! { |package| package["version"] }
|
36
36
|
if results.size == 1
|
@@ -56,6 +56,18 @@ module Licensed
|
|
56
56
|
result
|
57
57
|
end
|
58
58
|
|
59
|
+
# Returns parsed package metadata returned from `npm list`
|
60
|
+
def package_metadata
|
61
|
+
return @package_metadata if defined?(@package_metadata)
|
62
|
+
|
63
|
+
@package_metadata = begin
|
64
|
+
JSON.parse(package_metadata_command)
|
65
|
+
rescue JSON::ParserError => e
|
66
|
+
raise Licensed::Sources::Source::Error,
|
67
|
+
"Licensed was unable to parse the output from 'npm list'. Please run 'npm list --json --long' and check for errors. Error: #{e.message}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
59
71
|
# Returns the output from running `npm list` to get package metadata
|
60
72
|
def package_metadata_command
|
61
73
|
args = %w(--json --long)
|
@@ -36,7 +36,7 @@ module Licensed
|
|
36
36
|
def packages
|
37
37
|
return [] if yarn_package_tree.nil?
|
38
38
|
all_dependencies = {}
|
39
|
-
recursive_dependencies(
|
39
|
+
recursive_dependencies(yarn_package_tree).each do |name, results|
|
40
40
|
results.uniq! { |package| package["version"] }
|
41
41
|
if results.size == 1
|
42
42
|
# if there is only one package for a name, reference it by name
|
@@ -55,26 +55,34 @@ module Licensed
|
|
55
55
|
|
56
56
|
# Recursively parse dependency JSON data. Returns a hash mapping the
|
57
57
|
# package name to it's metadata
|
58
|
-
def recursive_dependencies(
|
58
|
+
def recursive_dependencies(dependencies, result = {})
|
59
59
|
dependencies.each do |dependency|
|
60
60
|
# "shadow" indicate a dependency requirement only, not a
|
61
61
|
# resolved package identifier
|
62
62
|
next if dependency["shadow"]
|
63
63
|
name, _, version = dependency["name"].rpartition("@")
|
64
64
|
|
65
|
-
# the dependency should be found under the parent's "node_modules" path
|
66
|
-
dependency_path = path.join("node_modules", name)
|
67
65
|
(result[name] ||= []) << {
|
68
66
|
"id" => dependency["name"],
|
69
67
|
"name" => name,
|
70
68
|
"version" => version,
|
71
|
-
"path" =>
|
69
|
+
"path" => dependency_paths[dependency["name"]]
|
72
70
|
}
|
73
|
-
recursive_dependencies(
|
71
|
+
recursive_dependencies(dependency["children"], result)
|
74
72
|
end
|
75
73
|
result
|
76
74
|
end
|
77
75
|
|
76
|
+
# Returns a hash that maps all dependency names to their location on disk
|
77
|
+
# by parsing every package.json file under node_modules.
|
78
|
+
def dependency_paths
|
79
|
+
@dependency_paths ||= Dir.glob(config.pwd.join("node_modules/**/package.json")).each_with_object({}) do |file, hsh|
|
80
|
+
dirname = File.dirname(file)
|
81
|
+
json = JSON.parse(File.read(file))
|
82
|
+
hsh["#{json["name"]}@#{json["version"]}"] = dirname
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
78
86
|
# Finds and returns the yarn package tree listing from `yarn list` output
|
79
87
|
def yarn_package_tree
|
80
88
|
return @yarn_package_tree if defined?(@yarn_package_tree)
|
data/lib/licensed/version.rb
CHANGED
data/licensed.gemspec
CHANGED
@@ -38,5 +38,4 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_development_dependency "rubocop", "~> 0.49", "< 0.67"
|
39
39
|
spec.add_development_dependency "rubocop-github", "~> 0.6"
|
40
40
|
spec.add_development_dependency "byebug", "~> 10.0.0"
|
41
|
-
spec.add_development_dependency "spy", "~> 1.0.0"
|
42
41
|
end
|
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: 2.
|
4
|
+
version: 2.14.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: licensee
|
@@ -218,20 +218,6 @@ dependencies:
|
|
218
218
|
- - "~>"
|
219
219
|
- !ruby/object:Gem::Version
|
220
220
|
version: 10.0.0
|
221
|
-
- !ruby/object:Gem::Dependency
|
222
|
-
name: spy
|
223
|
-
requirement: !ruby/object:Gem::Requirement
|
224
|
-
requirements:
|
225
|
-
- - "~>"
|
226
|
-
- !ruby/object:Gem::Version
|
227
|
-
version: 1.0.0
|
228
|
-
type: :development
|
229
|
-
prerelease: false
|
230
|
-
version_requirements: !ruby/object:Gem::Requirement
|
231
|
-
requirements:
|
232
|
-
- - "~>"
|
233
|
-
- !ruby/object:Gem::Version
|
234
|
-
version: 1.0.0
|
235
221
|
description: Licensed automates extracting and validating the licenses of dependencies.
|
236
222
|
email:
|
237
223
|
- opensource+licensed@github.com
|