licensed 2.7.0 → 2.8.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: 4b2b964bfef1d9dd5d12c96a4586a4e1815d530a744c09484b548e1505a01a22
4
- data.tar.gz: a14d76ad21ab8fb742f698eb0ca90702fb154184b5e887313f8f7a7f894a6437
3
+ metadata.gz: 2613c80ad97c8d19cea10560588a08406388e1860b21c18bfbd322843db428cc
4
+ data.tar.gz: b34fc3f921feccd667898554166d69cb8d7b327e3756c30a3e418364d57cc4a6
5
5
  SHA512:
6
- metadata.gz: 46689f9c144234c03de03c3adc9ee8cf11042d51047bcd83321eac9e1fd9d03a974f0f1757777da831e105e784153d06a4f48ea57b4cbda8079c0221074212f5
7
- data.tar.gz: 5e1fe805637db57b6d16b0cc0f6ff8dfe3d56fd5aa1d70ffc19c06cc41764afe98b20917697de45ca338a22fe3aa1fcfa2491e9c9f90db393b4b35d38de34dc4
6
+ metadata.gz: 720754f1245f1043a2ff4721e0c2b7a403d020cb886277992d1d56a4c2145c588514fdcb18c3a1cd5aaf0d9409a5f839d73691ef0b167fbce69304c9aaf061ed
7
+ data.tar.gz: f33e96346dbb63b48f78de856094992fa4bf58acd5ff811e9193e8e65e71308d91f4a4dc54bfa2b5b80bba1c3fc5348d94454bc00ddb7d012c20ecbed26ba441
@@ -16,6 +16,8 @@ jobs:
16
16
  uses: actions/setup-node@v1
17
17
  with:
18
18
  node-version: 8
19
+ - name: Install Bower
20
+ run: npm install -g bower
19
21
  - name: Set up Ruby
20
22
  uses: actions/setup-ruby@v1
21
23
  with:
@@ -340,3 +342,35 @@ jobs:
340
342
  run: script/source-setup/pipenv
341
343
  - name: Run tests
342
344
  run: script/test pipenv
345
+
346
+ yarn:
347
+ runs-on: ubuntu-latest
348
+ strategy:
349
+ matrix:
350
+ # not using 1.0.0 because it doesn't support `yarn list --production`
351
+ yarn_version: [ 1.4.0, latest ]
352
+ steps:
353
+ - uses: actions/checkout@master
354
+ - name: Setup node
355
+ uses: actions/setup-node@v1
356
+ with:
357
+ node-version: 12
358
+ - name: Install Yarn
359
+ run: npm install -g yarn@${YARN_VERSION}
360
+ env:
361
+ YARN_VERSION: ${{ matrix.yarn_version }}
362
+ - name: Set up Ruby
363
+ uses: actions/setup-ruby@v1
364
+ with:
365
+ ruby-version: 2.6.x
366
+ - run: bundle lock
367
+ - uses: actions/cache@preview
368
+ with:
369
+ path: vendor/gems
370
+ key: ${{ runner.os }}-gem-2.6.x-${{ hashFiles(format('{0}{1}', github.workspace, '/Gemfile.lock')) }}
371
+ - name: Bootstrap
372
+ run: script/bootstrap
373
+ - name: Set up fixtures
374
+ run: script/source-setup/yarn
375
+ - name: Run tests
376
+ run: script/test yarn
data/.gitignore CHANGED
@@ -12,26 +12,39 @@
12
12
  test/fixtures/bundler/.bundle/
13
13
  test/fixtures/bundler/vendor/
14
14
  test/fixtures/bundler/Gemfile.lock
15
+
15
16
  test/fixtures/bower/bower_components
17
+
16
18
  test/fixtures/npm/node_modules
17
19
  test/fixtures/npm/package-lock.json
20
+
18
21
  test/fixtures/go/src/*
19
22
  test/fixtures/go/pkg
20
23
  !test/fixtures/go/src/test
21
24
  !test/fixtures/go/src/modules_test
25
+
22
26
  test/fixtures/cabal/*
23
27
  !test/fixtures/cabal/app*
28
+
24
29
  test/fixtures/git_submodule/*
25
30
  !test/fixtures/git_submodule/README
31
+
26
32
  test/fixtures/pip/venv
33
+
27
34
  test/fixtures/pipenv/Pipfile.lock
35
+
28
36
  !test/fixtures/migrations/**/*
37
+
29
38
  test/fixtures/composer/**/*
30
39
  !test/fixtures/composer/composer.json
40
+
31
41
  test/fixtures/mix/_build
32
42
  test/fixtures/mix/deps
33
43
  test/fixtures/mix/mix.lock
34
44
 
45
+ test/fixtures/yarn/*
46
+ !test/fixtures/yarn/package.json
47
+
35
48
  vendor/licenses
36
49
  .licenses
37
50
  *.gem
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 2.8.0
10
+ 2020-01-03
11
+
12
+ ### Added
13
+ - Yarn source (https://github.com/github/licensed/pull/232, https://github.com/github/licensed/pull/233, https://github.com/github/licensed/pull/236)
14
+ - NPM source has a new option to include non-production dependencies (https://github.com/github/licensed/pull/231)
15
+
16
+ ### Fixed
17
+ - Cabal source will no longer crash if packages aren't found (https://github.com/github/licensed/pull/230)
18
+
9
19
  ## 2.7.0
10
20
  2019-11-10
11
21
 
@@ -255,4 +265,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
255
265
 
256
266
  Initial release :tada:
257
267
 
258
- [Unreleased]: https://github.com/github/licensed/compare/2.7.0...HEAD
268
+ [Unreleased]: https://github.com/github/licensed/compare/2.8.0...HEAD
data/README.md CHANGED
@@ -25,11 +25,11 @@ See the [migration documentation](./docs/migrating_to_newer_versions.md) for mor
25
25
 
26
26
  Licensed uses the `libgit2` bindings for Ruby provided by `rugged`. `rugged` requires `cmake` and `pkg-config` which you may need to install before you can install Licensed.
27
27
 
28
- > Ubuntu
28
+ > Ubuntu
29
29
 
30
30
  sudo apt-get install cmake pkg-config
31
31
 
32
- > OS X
32
+ > OS X
33
33
 
34
34
  brew install cmake pkg-config
35
35
 
@@ -110,6 +110,7 @@ Dependencies will be automatically detected for all of the following sources by
110
110
  1. [Pipenv](./docs/sources/pipenv.md)
111
111
  1. [Git Submodules (git_submodule)](./docs/sources/git_submodule.md)
112
112
  1. [Mix](./docs/sources/mix.md)
113
+ 1. [Yarn](./docs/sources/yarn.md)
113
114
 
114
115
  You can disable any of them in the configuration file:
115
116
 
@@ -64,7 +64,7 @@ name: 'My application'
64
64
  # If not set, defaults to a git repository root
65
65
  root: 'relative/path/from/configuration/file/directory'
66
66
 
67
- # Path is relative to configuration root
67
+ # Path is relative to configuration root and specifies where cached metadata will be stored.
68
68
  # If not set, defaults to '.licenses'
69
69
  cache_path: 'relative/path/to/cache'
70
70
 
@@ -78,16 +78,23 @@ sources:
78
78
  bower: true
79
79
  bundler: false
80
80
 
81
- # Dependencies with these licenses are allowed by default.
81
+ # Dependencies with these licenses are allowed and will not raise errors or warnings.
82
+ # This list does not have a default value and is required for `licensed status`
83
+ # to succeed.
82
84
  allowed:
83
85
  - mit
84
86
  - apache-2.0
85
87
  - bsd-2-clause
86
88
  - bsd-3-clause
87
89
  - cc0-1.0
88
-
89
- # These dependencies are explicitly ignored.
90
- # They shouldn't be cached at all, and will not have cached metadata written to the repo.
90
+ - isc
91
+
92
+ # These dependencies are ignored during enumeration.
93
+ # They will not be cached, and will not raise errors or warnings.
94
+ # This configuration is intended to be used for dependencies that don't need to
95
+ # be included for compliance purposes, such as other projects owned by the current
96
+ # project's owner, internal dependencies, and dependencies that aren't shipped with
97
+ # the project like test frameworks.
91
98
  ignored:
92
99
  bundler:
93
100
  - some-internal-gem
@@ -101,8 +108,10 @@ ignored:
101
108
  # comparisons use the FNM_CASEFOLD and FNM_PATHNAME flags
102
109
  - github.com/internal-package/**/*
103
110
 
104
- # These dependencies have been reviewed.
105
- # They need to be cached and checked, but do not have a license found that matches the allowed configured licenses.
111
+ # These dependencies have licenses not on the `allowed` list and have been reviewed.
112
+ # They will be cached and checked, but will not raise errors or warnings for a
113
+ # non-allowed license. Dependencies on this list will still raise errors if
114
+ # license text cannot be found for the dependency.
106
115
  reviewed:
107
116
  bundler:
108
117
  - bcrypt-ruby
@@ -1,3 +1,12 @@
1
1
  # NPM
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
+
5
+ ### Including development dependencies
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.
8
+
9
+ ```yml
10
+ npm:
11
+ production_only: false
12
+ ```
@@ -0,0 +1,16 @@
1
+ # Yarn
2
+
3
+ The yarn source will detect dependencies when `package.json` and `yarn.lock` are found at an app's `source_path`.
4
+
5
+ It uses `yarn list` to enumerate dependencies and `yarn info` to get metadata on each package.
6
+
7
+ ### Including development dependencies
8
+
9
+ Yarn versions < 1.3.0 will always include non-production dependencies due to a bug in those yarn versions.
10
+
11
+ Starting with yarn version >= 1.3.0, the yarn source excludes non-production dependencies by default. To include development and test dependencies, set `production_only: false` in `.licensed.yml`.
12
+
13
+ ```yml
14
+ yarn:
15
+ production_only: false
16
+ ```
@@ -15,5 +15,6 @@ module Licensed
15
15
  require "licensed/sources/pipenv"
16
16
  require "licensed/sources/gradle"
17
17
  require "licensed/sources/mix"
18
+ require "licensed/sources/yarn"
18
19
  end
19
20
  end
@@ -31,24 +31,25 @@ module Licensed
31
31
 
32
32
  # Returns a list of all detected packages
33
33
  def packages
34
- missing = []
35
34
  package_ids = Set.new
36
35
  cabal_file_dependencies.each do |target|
37
- name, version = target.split(/\s/, 2)
36
+ name = target.split(/\s/)[0]
38
37
  package_id = cabal_package_id(name)
39
38
  if package_id.nil?
40
- missing << { "name" => name, "version" => version, "error" => "package not found" }
39
+ package_ids << target
41
40
  else
42
41
  recursive_dependencies([package_id], package_ids)
43
42
  end
44
43
  end
45
44
 
46
- Parallel.map(package_ids) { |id| package_info(id) }.concat(missing)
45
+ Parallel.map(package_ids) { |id| package_info(id) }
47
46
  end
48
47
 
49
48
  # Returns the packages document directory and search root directory
50
49
  # as an array
51
50
  def package_docs_dirs(package)
51
+ return [nil, nil] if package.nil? || package.empty?
52
+
52
53
  unless package["haddock-html"]
53
54
  # default to a local vendor directory if haddock-html property
54
55
  # isn't available
@@ -78,18 +79,17 @@ module Licensed
78
79
  # Recursively finds the dependencies for each cabal package.
79
80
  # Returns a `Set` containing the package names for all dependencies
80
81
  def recursive_dependencies(package_names, results = Set.new)
81
- return [] if package_names.nil? || package_names.empty?
82
+ return results if package_names.nil? || package_names.empty?
82
83
 
83
84
  new_packages = Set.new(package_names) - results
84
- return [] if new_packages.empty?
85
+ return results if new_packages.empty?
85
86
 
86
87
  results.merge new_packages
87
88
 
88
89
  dependencies = Parallel.map(new_packages, &method(:package_dependencies)).flatten
89
90
 
90
- return results if dependencies.empty?
91
-
92
- results.merge recursive_dependencies(dependencies, results)
91
+ recursive_dependencies(dependencies, results)
92
+ results
93
93
  end
94
94
 
95
95
  # Returns an array of dependency package names for the cabal package
@@ -108,7 +108,10 @@ module Licensed
108
108
 
109
109
  # Returns package information as a hash for the given id
110
110
  def package_info(id)
111
- package_info_command(id).lines.each_with_object({}) do |line, info|
111
+ info = package_info_command(id).strip
112
+ return missing_package(id) if info.empty?
113
+
114
+ info.lines.each_with_object({}) do |line, info|
112
115
  key, value = line.split(":", 2).map(&:strip)
113
116
  next unless key && value
114
117
 
@@ -216,6 +219,17 @@ module Licensed
216
219
  def ghc?
217
220
  @ghc ||= Licensed::Shell.tool_available?("ghc")
218
221
  end
222
+
223
+ # Returns a package info structure with an error set
224
+ def missing_package(id)
225
+ name, _, version = if id.index(/\s/).nil?
226
+ id.rpartition("-") # e.g. to match the right-most dash from ipid fused-effects-1.0.0.0
227
+ else
228
+ id.partition(/\s/) # e.g. to match the left-most space from constraint fused-effects > 1.0.0.0
229
+ end
230
+
231
+ { "name" => name, "version" => version, "error" => "package not found" }
232
+ end
219
233
  end
220
234
  end
221
235
  end
@@ -57,13 +57,20 @@ module Licensed
57
57
 
58
58
  # Returns the output from running `npm list` to get package metadata
59
59
  def package_metadata_command
60
- Licensed::Shell.execute("npm", "list", "--json", "--production", "--long", allow_failure: true)
60
+ args = %w(--json --long)
61
+ args << "--production" unless include_non_production?
62
+ Licensed::Shell.execute("npm", "list", *args, allow_failure: true)
61
63
  end
62
64
 
63
65
  # Returns true if a yarn.lock file exists in the current directory
64
66
  def yarn_lock_present
65
67
  @yarn_lock_present ||= File.exist?(config.pwd.join("yarn.lock"))
66
68
  end
69
+
70
+ # Returns whether to include non production dependencies based on the licensed configuration settings
71
+ def include_non_production?
72
+ config.dig("npm", "production_only") == false
73
+ end
67
74
  end
68
75
  end
69
76
  end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+ require "json"
3
+
4
+ module Licensed
5
+ module Sources
6
+ class Yarn < Source
7
+ # `yarn licenses list --json` returns data in a table format with header
8
+ # ordering specified in the output. Look for these specific headers and use
9
+ # their indices to get data from the table body
10
+ YARN_NAME_HEAD = "Name".freeze
11
+ YARN_VERSION_HEAD = "Version".freeze
12
+ YARN_URL_HEAD = "URL".freeze
13
+
14
+ def enabled?
15
+ return unless Licensed::Shell.tool_available?("yarn")
16
+
17
+ config.pwd.join("package.json").exist? && config.pwd.join("yarn.lock").exist?
18
+ end
19
+
20
+ def enumerate_dependencies
21
+ packages.map do |name, package|
22
+ Dependency.new(
23
+ name: name,
24
+ version: package["version"],
25
+ path: package["path"],
26
+ metadata: {
27
+ "type" => Yarn.type,
28
+ "name" => package["name"],
29
+ "homepage" => dependency_urls[package["id"]]
30
+ }
31
+ )
32
+ end
33
+ end
34
+
35
+ # Finds packages that the current project relies on
36
+ def packages
37
+ return [] if yarn_package_tree.nil?
38
+ all_dependencies = {}
39
+ recursive_dependencies(config.pwd, yarn_package_tree).each do |name, results|
40
+ results.uniq! { |package| package["version"] }
41
+ if results.size == 1
42
+ # if there is only one package for a name, reference it by name
43
+ all_dependencies[name] = results[0]
44
+ else
45
+ # if there is more than one package for a name, reference each by
46
+ # "<name>-<version>"
47
+ results.each do |package|
48
+ all_dependencies["#{name}-#{package["version"]}"] = package
49
+ end
50
+ end
51
+ end
52
+
53
+ all_dependencies
54
+ end
55
+
56
+ # Recursively parse dependency JSON data. Returns a hash mapping the
57
+ # package name to it's metadata
58
+ def recursive_dependencies(path, dependencies, result = {})
59
+ dependencies.each do |dependency|
60
+ # "shadow" indicate a dependency requirement only, not a
61
+ # resolved package identifier
62
+ next if dependency["shadow"]
63
+ name, _, version = dependency["name"].rpartition("@")
64
+
65
+ # the dependency should be found under the parent's "node_modules" path
66
+ dependency_path = path.join("node_modules", name)
67
+ (result[name] ||= []) << {
68
+ "id" => dependency["name"],
69
+ "name" => name,
70
+ "version" => version,
71
+ "path" => dependency_path
72
+ }
73
+ recursive_dependencies(dependency_path, dependency["children"], result)
74
+ end
75
+ result
76
+ end
77
+
78
+ # Finds and returns the yarn package tree listing from `yarn list` output
79
+ def yarn_package_tree
80
+ return @yarn_package_tree if defined?(@yarn_package_tree)
81
+ @yarn_package_tree = begin
82
+ # parse all lines of output to json and find one that is "type": "tree"
83
+ tree = yarn_list_command.lines
84
+ .map(&:strip)
85
+ .map(&JSON.method(:parse))
86
+ .find { |json| json["type"] == "tree" }
87
+ tree&.dig("data", "trees")
88
+ end
89
+ end
90
+
91
+ # Returns a mapping of unique dependency identifiers to urls
92
+ def dependency_urls
93
+ @dependency_urls ||= begin
94
+ table = yarn_licenses_command.lines
95
+ .map(&:strip)
96
+ .map(&JSON.method(:parse))
97
+ .find { |json| json["type"] == "table" }
98
+ return [] if table.nil?
99
+
100
+ head = table.dig("data", "head")
101
+ return [] if head.nil?
102
+
103
+ name_index = head.index YARN_NAME_HEAD
104
+ version_index = head.index YARN_VERSION_HEAD
105
+ url_index = head.index YARN_URL_HEAD
106
+ return [] if name_index.nil? || version_index.nil? || url_index.nil?
107
+
108
+ body = table.dig("data", "body")
109
+ return [] if body.nil?
110
+
111
+ body.each_with_object({}) do |row, hsh|
112
+ id = "#{row[name_index]}@#{row[version_index]}"
113
+ hsh[id] = row[url_index]
114
+ end
115
+ end
116
+ end
117
+
118
+ # Returns the output from running `yarn list` to get project dependencies
119
+ def yarn_list_command
120
+ args = %w(--json -s --no-progress)
121
+ args << "--production" unless include_non_production?
122
+ Licensed::Shell.execute("yarn", "list", *args, allow_failure: true)
123
+ end
124
+
125
+ # Returns the output from running `yarn licenses list` to get project urls
126
+ def yarn_licenses_command
127
+ args = %w(--json -s --no-progress)
128
+ args << "--production" unless include_non_production?
129
+ Licensed::Shell.execute("yarn", "licenses", "list", *args, allow_failure: true)
130
+ end
131
+
132
+ # Returns whether to include non production dependencies based on the licensed configuration settings
133
+ def include_non_production?
134
+ config.dig("yarn", "production_only") == false
135
+ end
136
+ end
137
+ end
138
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "2.7.0".freeze
3
+ VERSION = "2.8.0".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ if [ -z "$(which yarn)" ]; then
5
+ echo "A local yarn installation is required for yarn development." >&2
6
+ exit 127
7
+ fi
8
+
9
+ # setup test fixtures
10
+ BASE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
11
+ cd $BASE_PATH/test/fixtures/yarn
12
+
13
+ if [ "$1" == "-f" ]; then
14
+ find . -not -regex "\.*" -and -not -name "package\.json" -print0 | xargs -0 rm -rf
15
+ fi
16
+
17
+ yarn install
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.7.0
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-10 00:00:00.000000000 Z
11
+ date: 2020-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee
@@ -254,6 +254,7 @@ files:
254
254
  - docs/sources/pip.md
255
255
  - docs/sources/pipenv.md
256
256
  - docs/sources/stack.md
257
+ - docs/sources/yarn.md
257
258
  - exe/licensed
258
259
  - lib/licensed.rb
259
260
  - lib/licensed/cli.rb
@@ -293,6 +294,7 @@ files:
293
294
  - lib/licensed/sources/pip.rb
294
295
  - lib/licensed/sources/pipenv.rb
295
296
  - lib/licensed/sources/source.rb
297
+ - lib/licensed/sources/yarn.rb
296
298
  - lib/licensed/ui/shell.rb
297
299
  - lib/licensed/version.rb
298
300
  - licensed.gemspec
@@ -314,6 +316,7 @@ files:
314
316
  - script/source-setup/npm
315
317
  - script/source-setup/pip
316
318
  - script/source-setup/pipenv
319
+ - script/source-setup/yarn
317
320
  - script/test
318
321
  homepage: https://github.com/github/licensed
319
322
  licenses: