licensed 2.13.0 → 2.14.4

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: a4477f07cae2650a7d8679a9042f73a7d14d8de019088be22d09f30e0f8af4c2
4
- data.tar.gz: b4cbd8769c1f98b1a0729e5d603ff08c15d2d5c5e4e8e029cd3bce7f69f395c1
3
+ metadata.gz: 1042edfc8e49ab1430a73001612f260fb20f80931139649f8b8ae6f044d74463
4
+ data.tar.gz: 386c548165ed4c4ed1b5b78131635552c11ec03f6a09e8f75e328d1446b129a7
5
5
  SHA512:
6
- metadata.gz: 83e7612e7a1fe2dbb77d48893c68db036630a45cdbc37f38f6630be0380231d9ac7fc0d37298d3a8a349d4bd43eb1dad64b7ec26a4b8d795806fb682091d94b7
7
- data.tar.gz: 26e4fed8cede2d4de43fc511a85a82507dcc0cbcc9a66537d39a189d533a7cfbb22fdf2be5ad242ae72f4943fde6676c23b0bdcdf906beeecef813369177c158
6
+ metadata.gz: c163d4d2bbffe0756b4aecfa353a99d8d3be92ea7fe5b536d00dc79b1581132b31bf69fd0947a85de095ec2d5604da547d175507a199427b1e74da25e8b63a03
7
+ data.tar.gz: 719df2438ad31e8e525f15ae2b9948f1fc3a0a83b5e72f2e109b10d498f65734d6ab49af99fb92486e31d4314a635a0a2d5bdca793bd51412804b76d9b48042a
@@ -1,20 +1,97 @@
1
- name: Create release
2
-
3
- on: create
1
+ name: Build and publish release assets
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: 'Commit-like version of github/licensed to build package at'
10
+ required: true
11
+ release_tag:
12
+ description: 'Release tag to upload built packages to'
13
+ required: false
4
14
 
5
15
  jobs:
6
- tag_filter:
16
+ vars:
17
+ name: "Gather values for remainder of steps"
7
18
  runs-on: ubuntu-latest
8
- if: startsWith(github.ref, 'refs/tags/')
19
+ outputs:
20
+ version: ${{ steps.get_version.outputs.result }}
21
+ upload_url: ${{ steps.get_url.outputs.result }}
22
+ ref: ${{ steps.get_ref.outputs.result }}
9
23
  steps:
10
- - run: exit 0
24
+ - id: get_version
25
+ name: Get package version
26
+ uses: actions/github-script@v3
27
+ with:
28
+ github-token: ${{ secrets.GITHUB_TOKEN }}
29
+ result-encoding: string
30
+ script: |
31
+ let version = "${{ github.event.release.tag_name }}"
32
+ if (!version) {
33
+ version = "${{ github.event.inputs.version }}"
34
+ }
35
+
36
+ if (!version) {
37
+ throw new Error("unable to find package build version")
38
+ }
39
+
40
+ return version
41
+
42
+ - id: get_url
43
+ name: Get release upload url
44
+ uses: actions/github-script@v3
45
+ with:
46
+ github-token: ${{ secrets.GITHUB_TOKEN }}
47
+ result-encoding: string
48
+ script: |
49
+ let uploadUrl = "${{ github.event.release.upload_url}}"
50
+ const tag = "${{ github.event.inputs.release_tag }}"
51
+ if (!uploadUrl && tag) {
52
+ const { data: release } = await github.repos.getReleaseByTag({
53
+ ...context.repo,
54
+ tag
55
+ })
56
+
57
+ if (!release.upload_url) {
58
+ throw new Error("unable to find a release upload url")
59
+ }
60
+
61
+ uploadUrl = release.upload_url
62
+ }
63
+
64
+ return uploadUrl
65
+
66
+ - id: get_ref
67
+ name: Get checkout ref for custom build scripts
68
+ uses: actions/github-script@v3
69
+ with:
70
+ github-token: ${{ secrets.GITHUB_TOKEN }}
71
+ result-encoding: string
72
+ script: |
73
+ let ref = "${{ github.event.release.tag_name }}"
74
+ if (!ref) {
75
+ ref = "${{ github.event.ref }}".replace(/refs\/[^\/]+\//, '')
76
+ }
77
+
78
+ if (!ref) {
79
+ throw new Error("unable to find a ref for action")
80
+ }
81
+
82
+ return ref
11
83
 
12
84
  package_linux:
85
+ needs: vars
13
86
  runs-on: ubuntu-latest
14
- needs: tag_filter
15
-
16
87
  steps:
17
88
  - uses: actions/checkout@v2
89
+ with:
90
+ # checkout at the ref for the action, separate from the target build version
91
+ # this allows running build scripts independent of the target version
92
+ ref: ${{needs.vars.outputs.ref}}
93
+ fetch-depth: 0
94
+
18
95
  - name: Set up Ruby 2.6
19
96
  uses: actions/setup-ruby@v1
20
97
  with:
@@ -23,19 +100,24 @@ jobs:
23
100
  - name: Build package
24
101
  run: script/packages/linux
25
102
  env:
26
- VERSION: ${{github.event.ref}}
103
+ VERSION: ${{needs.vars.outputs.version}}
27
104
 
28
105
  - uses: actions/upload-artifact@v2
29
106
  with:
30
- name: ${{github.event.ref}}-linux
31
- path: pkg/${{github.event.ref}}/licensed-${{github.event.ref}}-linux-x64.tar.gz
107
+ name: ${{needs.vars.outputs.version}}-linux
108
+ path: pkg/${{needs.vars.outputs.version}}/licensed-${{needs.vars.outputs.version}}-linux-x64.tar.gz
32
109
 
33
110
  package_mac:
111
+ needs: vars
34
112
  runs-on: macOS-latest
35
- needs: tag_filter
36
-
37
113
  steps:
38
114
  - uses: actions/checkout@v2
115
+ with:
116
+ # checkout at the ref for the action, separate from the target build version
117
+ # this allows running build scripts independent of the target version
118
+ ref: ${{needs.vars.outputs.ref}}
119
+ fetch-depth: 0
120
+
39
121
  - name: Set up Ruby 2.6
40
122
  uses: actions/setup-ruby@v1
41
123
  with:
@@ -44,44 +126,39 @@ jobs:
44
126
  - name: Build package
45
127
  run: script/packages/mac
46
128
  env:
47
- VERSION: ${{github.event.ref}}
129
+ VERSION: ${{needs.vars.outputs.version}}
48
130
 
49
131
  - uses: actions/upload-artifact@v2
50
132
  with:
51
- name: ${{github.event.ref}}-darwin
52
- path: pkg/${{github.event.ref}}/licensed-${{github.event.ref}}-darwin-x64.tar.gz
133
+ name: ${{needs.vars.outputs.version}}-darwin
134
+ path: pkg/${{needs.vars.outputs.version}}/licensed-${{needs.vars.outputs.version}}-darwin-x64.tar.gz
53
135
 
54
136
  build_gem:
137
+ needs: vars
55
138
  runs-on: ubuntu-latest
56
- needs: tag_filter
57
-
58
139
  steps:
59
140
  - uses: actions/checkout@v2
141
+ with:
142
+ # building a gem doesn't use a different ref from the version input
143
+ ref: ${{needs.vars.outputs.version}}
144
+
60
145
  - name: Set up Ruby 2.6
61
146
  uses: actions/setup-ruby@v1
62
147
  with:
63
148
  ruby-version: 2.6.x
64
149
 
65
150
  - name: Build gem
66
- run: gem build *.gemspec
151
+ run: gem build licensed.gemspec -o licensed-${{needs.vars.outputs.version}}.gem
67
152
 
68
153
  - uses: actions/upload-artifact@v2
69
154
  with:
70
- name: ${{github.event.ref}}-gem
71
- path: licensed-${{github.event.ref}}.gem
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:]]+"
155
+ name: ${{needs.vars.outputs.version}}-gem
156
+ path: licensed-${{needs.vars.outputs.version}}.gem
81
157
 
82
158
  upload_packages:
159
+ if: ${{ needs.vars.outputs.upload_url != '' }}
83
160
  runs-on: ubuntu-latest
84
- needs: [create_release]
161
+ needs: [vars, package_linux, package_mac, build_gem]
85
162
 
86
163
  steps:
87
164
  - name: Set up Ruby 2.6
@@ -92,32 +169,45 @@ jobs:
92
169
  - name: Download linux package
93
170
  uses: actions/download-artifact@v2
94
171
  with:
95
- name: ${{github.event.ref}}-linux
172
+ name: ${{needs.vars.outputs.version}}-linux
96
173
 
97
174
  - name: Download macOS package
98
175
  uses: actions/download-artifact@v2
99
176
  with:
100
- name: ${{github.event.ref}}-darwin
177
+ name: ${{needs.vars.outputs.version}}-darwin
101
178
 
102
179
  - name: Download gem
103
180
  uses: actions/download-artifact@v2
104
181
  with:
105
- name: ${{github.event.ref}}-gem
182
+ name: ${{needs.vars.outputs.version}}-gem
106
183
 
107
- - name: Publish packages to GitHub Release
108
- uses: Roang-zero1/github-upload-release-artifacts-action@v2.0.0
184
+ - name: Publish linux package
185
+ uses: actions/upload-release-asset@v1
186
+ env:
187
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
109
188
  with:
110
- args: licensed-${{github.event.ref}}-linux-x64.tar.gz licensed-${{github.event.ref}}-darwin-x64.tar.gz
189
+ upload_url: ${{ needs.vars.outputs.upload_url }}
190
+ asset_path: ./licensed-${{needs.vars.outputs.version}}-linux-x64.tar.gz
191
+ asset_name: licensed-${{needs.vars.outputs.version}}-linux-x64.tar.gz
192
+ asset_content_type: application/gzip
193
+
194
+ - name: Publish mac package
195
+ uses: actions/upload-release-asset@v1
111
196
  env:
112
- GITHUB_TOKEN: ${{secrets.API_AUTH_TOKEN}}
197
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
198
+ with:
199
+ upload_url: ${{ needs.vars.outputs.upload_url }}
200
+ asset_path: ./licensed-${{needs.vars.outputs.version}}-darwin-x64.tar.gz
201
+ asset_name: licensed-${{needs.vars.outputs.version}}-darwin-x64.tar.gz
202
+ asset_content_type: application/gzip
113
203
 
114
204
  - name: Publish gem to RubyGems
115
205
  run: |
116
206
  mkdir -p $HOME/.gem
117
207
  touch $HOME/.gem/credentials
118
208
  chmod 0600 $HOME/.gem/credentials
119
- printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
209
+ printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_KEY}\n" > $HOME/.gem/credentials
120
210
  gem push $GEM
121
211
  env:
122
- GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
123
- GEM: licensed-${{github.event.ref}}.gem
212
+ RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
213
+ GEM: licensed-${{needs.vars.outputs.version}}.gem
@@ -165,7 +165,7 @@ jobs:
165
165
  runs-on: ubuntu-latest
166
166
  strategy:
167
167
  matrix:
168
- go: [ '1.7.x', '1.10.x', '1.11.x', '1.12.x', '1.13.x', '1.14.x' ]
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,6 +6,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.14.4
10
+ 2021-02-09
11
+
12
+ ## Added
13
+ - `list` and `cache` commands optionally print output in JSON or YML formats using the `--format/-f` flag (https://github.com/github/licensed/pull/334)
14
+ - `list` command will include detected license keys using the `--licenses/-l` flag (https://github.com/github/licensed/pull/334)
15
+
16
+ ## 2.14.3
17
+ 2020-12-11
18
+
19
+ ## Fixed
20
+ - Auto-generating license text for a known license will no longer raise an error if the found license has no text (:tada: @Eun https://github.com/github/licensed/pull/328)
21
+
22
+ ## 2.14.2
23
+ 2020-11-20
24
+
25
+ ## Fixed
26
+ - Yarn source correctly finds dependency paths on disk (https://github.com/github/licensed/pull/326)
27
+ - Go source better handles finding dependencies that have been vendored (https://github.com/github/licensed/pull/323)
28
+
29
+ ## 2.14.1
30
+ 2020-10-09
31
+
32
+ ### Fixed
33
+ - Shell command output is encoded to UTF8 (https://github.com/github/licensed/pull/319)
34
+
35
+ ## 2.14.0
36
+ 2020-10-04
37
+
38
+ ### Added
39
+ - `reviewed` dependencies can use glob pattern matching (https://github.com/github/licensed/pull/313)
40
+
41
+ ### Fixed
42
+ - Fix configuring source path globs that expand into a single directory (https://github.com/github/licensed/pull/312)
43
+
9
44
  ## 2.13.0
10
45
  2020-09-23
11
46
 
@@ -351,4 +386,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
351
386
 
352
387
  Initial release :tada:
353
388
 
354
- [Unreleased]: https://github.com/github/licensed/compare/2.13.0...HEAD
389
+ [Unreleased]: https://github.com/github/licensed/compare/2.14.4...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-vxx.xx.xx
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. Tag and push: `git tag x.xx.xx; git push --tags`
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 pushing a new tag. In case that fails, the following steps can be performed manually
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. Create release for new tag at github/licensed.
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
 
@@ -12,3 +12,4 @@ RUN gem update --system && gem update bundler
12
12
  ENV CPPFLAGS="-P"
13
13
  ENV RUBYC="/usr/local/bin/rubyc"
14
14
  ENV LANG=C.UTF-8
15
+ ENV SSL_CERT_DIR="/etc/ssl/certs"
@@ -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 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.
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
@@ -12,9 +12,11 @@ module Licensed
12
12
  desc: "Path to licensed configuration file"
13
13
  method_option :sources, aliases: "-s", type: :array,
14
14
  desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
15
+ method_option :format, aliases: "-f", enum: ["yaml", "json"],
16
+ desc: "Output format"
15
17
  def cache
16
18
  run Licensed::Commands::Cache.new(config: config),
17
- force: options[:force], sources: options[:sources]
19
+ force: options[:force], sources: options[:sources], reporter: options[:format]
18
20
  end
19
21
 
20
22
  desc "status", "Check status of dependencies' cached licenses"
@@ -33,8 +35,12 @@ module Licensed
33
35
  desc: "Path to licensed configuration file"
34
36
  method_option :sources, aliases: "-s", type: :array,
35
37
  desc: "Individual source(s) to evaluate. Must also be enabled via configuration."
38
+ method_option :format, aliases: "-f", enum: ["yaml", "json"],
39
+ desc: "Output format"
40
+ method_option :licenses, aliases: "-l", type: :boolean,
41
+ desc: "Include detected licenses in output"
36
42
  def list
37
- run Licensed::Commands::List.new(config: config), sources: options[:sources]
43
+ run Licensed::Commands::List.new(config: config), sources: options[:sources], reporter: options[:format], licenses: options[:licenses]
38
44
  end
39
45
 
40
46
  desc "notices", "Generate a NOTICE file from cached records"
@@ -72,6 +72,12 @@ module Licensed
72
72
  # Returns whether the command succeeded for the application.
73
73
  def run_app(app)
74
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
+
75
81
  Dir.chdir app.source_path do
76
82
  begin
77
83
  # allow additional report data to be given by commands
@@ -41,6 +41,13 @@ module Licensed
41
41
  #
42
42
  # Returns true.
43
43
  def evaluate_dependency(app, source, dependency, report)
44
+ report["dependency"] = dependency.name
45
+ report["version"] = dependency.version
46
+
47
+ if options[:licenses]
48
+ report["license"] = dependency.license_key
49
+ end
50
+
44
51
  true
45
52
  end
46
53
  end
@@ -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"]]).include?(dependency["name"])
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
- # return the original configuration if glob didn't result in multiple paths
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
- # map the expanded paths to new application configurations
167
- expanded_source_paths.map do |path|
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
- # update configured values for name and cache_path for uniqueness.
171
- # this is only needed when values are explicitly set, AppConfiguration
172
- # will handle configurations that don't have these explicitly set
173
- dir_name = File.basename(path)
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.
@@ -142,6 +142,7 @@ module Licensed
142
142
  def generated_license_contents
143
143
  return unless license
144
144
  return if license.key == "other"
145
+ return if license.text.nil?
145
146
 
146
147
  # strip copyright clauses and any extra newlines
147
148
  # many package managers don't provide enough information to
@@ -75,7 +75,9 @@ module Licensed
75
75
  def report_dependency(dependency)
76
76
  super do |report|
77
77
  result = yield report
78
- shell.info " #{dependency.name} (#{dependency.version})"
78
+ info = "#{dependency.name} (#{dependency.version})"
79
+ info = "#{info}: #{report["license"]}" if report["license"]
80
+ shell.info " #{info}"
79
81
 
80
82
  result
81
83
  end
@@ -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? || allow_failure
13
- stdout.strip
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
@@ -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 = non_vendored_path(package["ImportPath"], root_package["ImportPath"])
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["ImportPath"]
83
+ import_path = non_vendored_import_path(package)
85
84
  return false unless import_path
86
85
 
87
- # true if go standard packages includes the import path as given
88
- return true if go_std_packages.include?(import_path)
89
- return true if go_std_packages.include?("vendor/#{import_path}")
90
- return true if go_std_packages.include?(import_path.sub("golang.org", "internal"))
91
-
92
- # additional checks are only for vendored dependencies - return false
93
- # if package isn't vendored
94
- non_vendored_import_path = non_vendored_path(import_path, root_package["ImportPath"])
95
- return false unless non_vendored_import_path
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["ImportPath"]
110
- import_path = package["ImportPath"]
111
- import_path.start_with?(root_package["ImportPath"]) && !import_path.include?("vendor/")
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
- return package["Dir"].match("^(.*/vendor)/.*$")[1] if vendored_path?(package["Dir"], config.root)
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
- # Returns whether a package is vendored or not based on a base path and
171
- # whether the path contains a vendor component
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
- # path - Package path to test
174
- # base - The base path that the input must start with
175
- def vendored_path?(path, base)
176
- return false if path.nil? || base.nil?
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 path parameter without the vendor component if one is found
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
- # path - Package path with vendor component
183
- # base - The base path that the input must start with
184
- def non_vendored_path(path, base)
185
- return unless path
186
- return unless vendored_path?(path, base)
187
- path.split("vendor/")[1]
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
@@ -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(config.pwd, yarn_package_tree).each do |name, results|
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(path, dependencies, result = {})
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" => dependency_path
69
+ "path" => dependency_paths[dependency["name"]]
72
70
  }
73
- recursive_dependencies(dependency_path, dependency["children"], result)
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)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "2.13.0".freeze
3
+ VERSION = "2.14.4".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
@@ -34,6 +34,9 @@ build_linux_local() {
34
34
  sudo apt-get update
35
35
  sudo apt-get install -y --no-install-recommends cmake make gcc pkg-config squashfs-tools curl bison git rsync
36
36
 
37
+ sudo gem update --system
38
+ sudo gem update bundler
39
+
37
40
  RUBYC="$BASE_DIR/bin/rubyc-linux"
38
41
  if [ ! -f "$RUBYC" ]; then
39
42
  mkdir -p "$(dirname "$RUBYC")"
@@ -42,6 +45,7 @@ build_linux_local() {
42
45
  fi
43
46
 
44
47
  export CPPFLAGS="-P"
48
+ export SSL_CERT_DIR="/etc/ssl/certs"
45
49
  export RUBYC
46
50
  "$BASE_DIR"/script/packages/build
47
51
  }
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.13.0
4
+ version: 2.14.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-24 00:00:00.000000000 Z
11
+ date: 2021-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee