licensed 1.3.4 → 1.4.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
  SHA1:
3
- metadata.gz: aafa9f6256e89db107b0d7c421a95e33b8b3ecaa
4
- data.tar.gz: 9a8141a9ce955d183156404f591d0f16d73bda16
3
+ metadata.gz: 5c9bec838ecfcc1a05a17a40200bd1c166197d01
4
+ data.tar.gz: 87dad427c0c7b78f05015031b8be76132ccb96f4
5
5
  SHA512:
6
- metadata.gz: 72293e38a7c2dd14a1594f3a9cc68d9d7c36eb6de376d581703ab424b750cf5d429067b827380153da5622c6aa0212a94339379ad763b2175beedb850cad3eac
7
- data.tar.gz: 8e4bb0f627d6ff93a2138a4eb80c755987597445629e94eb514af8b1d3522c5e85463f1aee858f9a4f45f8f45c88dfbc5adc9dcd2c239d6ba149497a66f17895
6
+ metadata.gz: b868455d7be394025fee42db87172e8722423750f9f938f345f253e036673a0ada06982b4c5012ce4f530d068fb6f4bdea0cf5cb43bfa07a1a28cb91f293ca9b
7
+ data.tar.gz: 1810f02787fa0133f93fa7d482190da18c5579abab12b3ec2f698a0ecdf60814a3bd75335144a50b03b62a4761e011a315cd6fc1a412a6203bacf6a325e572a0
data/.gitignore CHANGED
@@ -20,6 +20,8 @@ test/fixtures/go/pkg
20
20
  !test/fixtures/go/src/test
21
21
  test/fixtures/cabal/*
22
22
  !test/fixtures/cabal/app*
23
+ test/fixtures/git_submodule/*
24
+ !test/fixtures/git_submodule/README
23
25
 
24
26
  vendor/licenses
25
27
  .licenses
data/.travis.yml CHANGED
@@ -81,5 +81,11 @@ matrix:
81
81
  script: ./script/test pip
82
82
  env: NAME="pip"
83
83
 
84
+ - language: ruby
85
+ rvm: 2.4.0
86
+ before_script: ./script/source-setup/git_submodule
87
+ script: ./script/test git_submodule
88
+ env: NAME="git_submodule"
89
+
84
90
  notifications:
85
91
  disable: true
data/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 1.4.0 - 2018-10-20
10
+ ### Added
11
+ - Git Submodules dependency source :tada:
12
+ - Configuration option to explicitly set a root absolute path
13
+
14
+ ### Changes
15
+ - `COPYING` file is no longer matched as a legal file
16
+
17
+ ### Fixed
18
+ - NPM source will enumerate multiple versions of the same dependency
19
+ - Running Licensed outside of a Git repository no longer raises an error
20
+ - Packaging scripts will correctly return to the previous branch when the script is finished
21
+
9
22
  ## 1.3.4 - 2018-09-20
10
23
  ### Changes
11
24
  - Bundler source will avoid looking for a gemspec file when possible
@@ -77,4 +90,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77
90
 
78
91
  Initial release :tada:
79
92
 
80
- [Unreleased]: https://github.com/github/licensed/compare/1.3.4...HEAD
93
+ [Unreleased]: https://github.com/github/licensed/compare/1.4.0...HEAD
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Licensed
2
2
 
3
- Licensed is a Ruby gem to cache the licenses of dependencies and check their status.
3
+ Licensed caches the licenses of dependencies and checks their status.
4
+
5
+ Licensed is available as a Ruby gem for Ruby environments, and as a self-contained executable for non-Ruby environments.
4
6
 
5
7
  Licensed is **not** a complete open source license compliance solution. Please understand the important [disclaimer](#disclaimer) below to make appropriate use of Licensed.
6
8
 
@@ -12,6 +14,8 @@ Licensed is in active development and currently used at GitHub. See the [open i
12
14
 
13
15
  ## Installation
14
16
 
17
+ ### With a Gemfile
18
+
15
19
  Add this line to your application's Gemfile:
16
20
 
17
21
  ```ruby
@@ -24,6 +28,19 @@ And then execute:
24
28
  $ bundle
25
29
  ```
26
30
 
31
+ ### As an executable
32
+
33
+ Download a package from GitHub and extract the executable. Executable packages are available for each release starting with version 1.2.0.
34
+
35
+ ```bash
36
+ $ curl -sSL https://github.com/github/licensed/releases/download/<version>/licensed-<version>-<os>-x64.tar.gz > licensed.tar.gz
37
+ $ tar -xzf licensed.tar.gz
38
+ $ rm -f licensed.tar.gz
39
+ $ ./licensed list
40
+ ```
41
+
42
+ For system wide usage, install licensed to a location on `$PATH`, e.g. `/usr/local/bin`.
43
+
27
44
  #### Dependencies
28
45
 
29
46
  Licensed uses the the `libgit2` bindings for Ruby provided by `rugged`. `rugged` has its own dependencies - `cmake` and `pkg-config` - which you may need to install before you can install Licensed.
@@ -81,6 +98,7 @@ Dependencies will be automatically detected for
81
98
  6. [Manifest lists](./docs/sources/manifests.md)
82
99
  7. [NPM](./docs/sources/npm.md)
83
100
  8. [Pip](./docs/sources/pip.md)
101
+ 9. [Git Submodules](./docs/sources/git_submodule.md)
84
102
 
85
103
  You can disable any of them in the configuration file:
86
104
 
@@ -118,10 +136,6 @@ if Licensed::Shell.tool_available?('bundle')
118
136
  end
119
137
  ```
120
138
 
121
- ## Packaging
122
-
123
- Licensed can be built into an exe and packaged for distribution to systems that don't have ruby already available. See the [packaging documentation](./docs/packaging.md) for details.
124
-
125
139
  ## Contributing
126
140
 
127
141
  Bug reports and pull requests are welcome on GitHub at https://github.com/github/licensed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org/) code of conduct. See [CONTRIBUTING](CONTRIBUTING.md) for more details.
@@ -4,6 +4,21 @@ A configuration file specifies the details of enumerating and operating on licen
4
4
 
5
5
  Configuration can be specified in either YML or JSON formats. Examples below are given in YML.
6
6
 
7
+ ## Configuration Paths
8
+
9
+ `licensed` requires a path to enumerate dependencies at (`source_path`) and a path to store cached metadata (`cache_path`).
10
+
11
+ To determine these paths across multiple environments where absolute paths will differ, a known root path is needed to evaluate relative paths against.
12
+ In using a root, relative source and cache paths can be specified in the configuration file.
13
+
14
+ When using a configuration file, the root property can be set as either a path that can be expanded from the configuration file directory using `File.expand_path`, or the value `true` to use the configuration file directory as the root.
15
+
16
+ When creating a `Licensed::Dependency` manually with a `root` property, the property must be an absolute path - no path expansion will occur.
17
+
18
+ If a root path is not specified, it will default to using the following, in order of precedence
19
+ 1. the root of the local git repository, if run inside a git repository
20
+ 2. the current directory
21
+
7
22
  ## Restricting sources
8
23
 
9
24
  The `sources` configuration property specifies which sources `licensed` will use to enumerate dependencies.
@@ -44,11 +59,16 @@ Configuration can be set up for single or multiple applications in the same repo
44
59
  # If not set, defaults to the directory name of `source_path`
45
60
  name: 'My application'
46
61
 
47
- # Path is relative to git repository root
62
+ # Path is relative to the location of the configuration file and specifies
63
+ # the root to expand all paths from
64
+ # If not set, defaults to a git repository root
65
+ root: 'relative/path/from/configuration/file/directory'
66
+
67
+ # Path is relative to configuration root
48
68
  # If not set, defaults to '.licenses'
49
69
  cache_path: 'relative/path/to/cache'
50
70
 
51
- # Path is relative to git repository root and specifies the working directory when enumerating dependencies
71
+ # Path is relative to configuration root and specifies the working directory when enumerating dependencies
52
72
  # Optional for single app configuration, required when specifying multiple apps
53
73
  # Defaults to current directory when running `licensed`
54
74
  source_path: 'relative/path/to/source'
@@ -0,0 +1,17 @@
1
+ # Git Submodules
2
+
3
+ The Git submodule source uses `git submodule foreach` CLI commands to enumerate dependencies and properties. The Git submodule dependency source requires `git` version 2.0 or greater to be available, that the project is a valid Git repository, and that submodules are fetched locally.
4
+
5
+ #### Nested submodules
6
+
7
+ Nested submodules are detected as long as the submodules have been fetched locally, i.e. `git submodule update --init --recursive` or a similar operation has been run. If a nested submodule has not been initialized, it will not be detected and no error is provided.
8
+
9
+ Dependencies for submodules will be cached at a path similar to their nested structure to avoid any clashes if a single repository is references as a submodule in multiple places. As an example if `my_project` uses `submodule_1`, and `submodule_2` uses `submodule_2`, the metadata files will be available at:
10
+
11
+ - <cache_path>
12
+ | - git_submodule
13
+ | - my_project.txt
14
+ | - my_project
15
+ | - submodule_1.txt
16
+ | - submodule_1
17
+ | - submodule_2.txt
data/lib/licensed.rb CHANGED
@@ -12,6 +12,7 @@ require "licensed/source/go"
12
12
  require "licensed/source/dep"
13
13
  require "licensed/source/cabal"
14
14
  require "licensed/source/pip"
15
+ require "licensed/source/git_submodule"
15
16
  require "licensed/configuration"
16
17
  require "licensed/command/cache"
17
18
  require "licensed/command/status"
@@ -30,7 +30,7 @@ module Licensed
30
30
 
31
31
  # ensure each dependency is cached
32
32
  dependencies.each do |dependency|
33
- name = dependency["name"]
33
+ name = dependency.name
34
34
  version = dependency["version"]
35
35
 
36
36
  names << name
@@ -10,7 +10,7 @@ module Licensed
10
10
 
11
11
  def run
12
12
  @config.apps.each do |app|
13
- @config.ui.info "Displaying dependencies for #{app['name']}"
13
+ @config.ui.info "Displaying dependencies for #{app["name"]}"
14
14
  Dir.chdir app.source_path do
15
15
  app.sources.each do |source|
16
16
  type = source.class.type
@@ -19,7 +19,7 @@ module Licensed
19
19
 
20
20
  source_dependencies = dependencies(app, source)
21
21
  source_dependencies.each do |dependency|
22
- @config.ui.info " Found #{dependency['name']} (#{dependency['version']})"
22
+ @config.ui.info " Found #{dependency.name} (#{dependency["version"]})"
23
23
  end
24
24
 
25
25
  @config.ui.confirm " * #{type} dependencies: #{source_dependencies.size}"
@@ -32,7 +32,7 @@ module Licensed
32
32
  def dependencies(app, source)
33
33
  source.dependencies
34
34
  .select { |d| !app.ignored?(d) }
35
- .sort_by { |d| d["name"] }
35
+ .sort_by { |d| d.name }
36
36
  end
37
37
 
38
38
  def success?
@@ -25,7 +25,8 @@ module Licensed
25
25
  @config.ui.info "Checking licenses for #{app['name']}: #{dependencies.size} dependencies"
26
26
 
27
27
  results = dependencies.map do |dependency|
28
- filename = app.cache_path.join(dependency["type"], "#{dependency["name"]}.txt")
28
+ name = dependency.name
29
+ filename = app.cache_path.join(dependency["type"], "#{name}.txt")
29
30
 
30
31
  warnings = []
31
32
 
@@ -27,18 +27,28 @@ module Licensed
27
27
  self["ignored"] ||= {}
28
28
  self["allowed"] ||= []
29
29
 
30
+ # default the root to the git repository root,
31
+ # or the current directory if no other options are available
32
+ self["root"] ||= Licensed::Git.repository_root || Dir.pwd
33
+
30
34
  verify_arg "source_path"
31
35
  verify_arg "cache_path"
32
36
  end
33
37
 
38
+ # Returns the path to the workspace root as a Pathname.
39
+ # Defaults to Licensed::Git.repository_root if not explicitly set
40
+ def root
41
+ Pathname.new(self["root"])
42
+ end
43
+
34
44
  # Returns the path to the app cache directory as a Pathname
35
45
  def cache_path
36
- Licensed::Git.repository_root.join(self["cache_path"])
46
+ root.join(self["cache_path"])
37
47
  end
38
48
 
39
49
  # Returns the path to the app source directory as a Pathname
40
50
  def source_path
41
- Licensed::Git.repository_root.join(self["source_path"])
51
+ root.join(self["source_path"])
42
52
  end
43
53
 
44
54
  def pwd
@@ -89,6 +99,8 @@ module Licensed
89
99
  self["allowed"] << license
90
100
  end
91
101
 
102
+ private
103
+
92
104
  def defaults_for(options, inherited_options)
93
105
  name = options["name"] || File.basename(options["source_path"])
94
106
  cache_path = inherited_options["cache_path"] || DEFAULT_CACHE_PATH
@@ -158,7 +170,7 @@ module Licensed
158
170
  return {} unless config_path.file?
159
171
 
160
172
  extension = config_path.extname.downcase.delete "."
161
- case extension
173
+ config = case extension
162
174
  when "json"
163
175
  JSON.parse(File.read(config_path))
164
176
  when "yml", "yaml"
@@ -166,6 +178,23 @@ module Licensed
166
178
  else
167
179
  raise LoadError, "Unknown file type #{extension} for #{config_path}"
168
180
  end
181
+
182
+ expand_config_roots(config, config_path)
183
+ config
184
+ end
185
+
186
+ # Expand any roots specified in a configuration file based on the configuration
187
+ # files directory.
188
+ def self.expand_config_roots(config, config_path)
189
+ if config["root"] == true
190
+ config["root"] = File.dirname(config_path)
191
+ elsif config["root"]
192
+ config["root"] = File.expand_path(config["root"], File.dirname(config_path))
193
+ end
194
+
195
+ if config["apps"]&.any?
196
+ config["apps"].each { |app_config| expand_config_roots(app_config, config_path) }
197
+ end
169
198
  end
170
199
 
171
200
  def default_options
@@ -3,13 +3,15 @@ require "licensee"
3
3
 
4
4
  module Licensed
5
5
  class Dependency < License
6
- LEGAL_FILES = /\A(AUTHORS|COPYING|NOTICE|LEGAL)(?:\..*)?\z/i
6
+ LEGAL_FILES = /\A(AUTHORS|NOTICE|LEGAL)(?:\..*)?\z/i
7
7
 
8
8
  attr_reader :path
9
9
  attr_reader :search_root
10
+ attr_reader :name
10
11
 
11
12
  def initialize(path, metadata = {})
12
13
  @search_root = metadata.delete("search_root")
14
+ @name = metadata.delete("path") || metadata["name"]
13
15
  super metadata
14
16
 
15
17
  self.path = path
data/lib/licensed/git.rb CHANGED
@@ -7,9 +7,16 @@ module Licensed
7
7
  @git ||= Licensed::Shell.tool_available?("git")
8
8
  end
9
9
 
10
+ def git_repo?
11
+ return false unless available?
12
+ !Licensed::Shell.execute("git", "status", allow_failure: true).empty?
13
+ end
14
+
15
+ # Returns the root of the current git repository
16
+ # or nil if not in a git repository.
10
17
  def repository_root
11
- return unless available?
12
- @root ||= Pathname.new(Licensed::Shell.execute("git", "rev-parse", "--show-toplevel"))
18
+ return unless git_repo?
19
+ Licensed::Shell.execute("git", "rev-parse", "--show-toplevel")
13
20
  end
14
21
 
15
22
  # Returns the most recent git SHA for a file or directory
@@ -17,7 +24,7 @@ module Licensed
17
24
  #
18
25
  # descriptor - file or directory to retrieve latest SHA for
19
26
  def version(descriptor)
20
- return unless available? && descriptor
27
+ return unless git_repo? && descriptor
21
28
  Licensed::Shell.execute("git", "rev-list", "-1", "HEAD", "--", descriptor, allow_failure: true)
22
29
  end
23
30
 
@@ -25,12 +32,13 @@ module Licensed
25
32
  #
26
33
  # sha - commit sha to retrieve date
27
34
  def commit_date(sha)
28
- return unless available? && sha
35
+ return unless git_repo? && sha
29
36
  Licensed::Shell.execute("git", "show", "-s", "-1", "--format=%ct", sha)
30
37
  end
31
38
 
39
+ # Returns the files in the git repository from `git ls-files --recurse-submodules`
32
40
  def files
33
- return unless available?
41
+ return unless git_repo?
34
42
  output = Licensed::Shell.execute("git", "ls-files", "--full-name", "--recurse-submodules")
35
43
  output.lines.map(&:strip)
36
44
  end
@@ -137,7 +137,7 @@ module Licensed
137
137
  Array(@config["cabal"]["ghc_package_db"]).map do |path|
138
138
  next "--#{path}" if %w(global user).include?(path)
139
139
  path = realized_ghc_package_path(path)
140
- path = File.expand_path(path, Licensed::Git.repository_root)
140
+ path = File.expand_path(path, @config.root)
141
141
 
142
142
  next unless File.exist?(path)
143
143
  "--package-db=#{path}"
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Licensed
4
+ module Source
5
+ class GitSubmodule
6
+ REMOTE_URL_ARGUMENT = "$(git remote get-url origin)".freeze
7
+ GIT_SUBMODULES_ARGUMENTS = [
8
+ "$displaypath", # path from repo root to submodule folder to find the name and submodule content
9
+ "$toplevel", # path to parent repository to calculate the ancestor chain
10
+ "$sha1", # use the commit reference of the submodule as the version
11
+ "$(git config --get remote.origin.url)", # use the configured remote origin url as the homepage
12
+ ].freeze
13
+
14
+ def self.type
15
+ "git_submodule"
16
+ end
17
+
18
+ def initialize(config)
19
+ @config = config
20
+ end
21
+
22
+ def enabled?
23
+ return false unless Licensed::Shell.tool_available?("git") && Licensed::Git.git_repo?
24
+ gitmodules_path.exist?
25
+ end
26
+
27
+ def dependencies
28
+ @dependencies ||= git_submodules_command.lines.map do |line|
29
+ displaypath, toplevel, version, homepage = line.strip.split
30
+ name = File.basename(displaypath)
31
+ submodule_path = if toplevel == @config.pwd.to_s
32
+ name
33
+ else
34
+ parent = File.basename(toplevel)
35
+ "#{submodule_paths[parent]}/#{name}"
36
+ end
37
+ submodule_paths[name] = submodule_path
38
+
39
+ Licensed::Dependency.new(@config.pwd.join(displaypath), {
40
+ "type" => self.class.type,
41
+ "name" => name,
42
+ "version" => version,
43
+ "homepage" => homepage,
44
+ "path" => submodule_path
45
+ })
46
+ end
47
+ end
48
+
49
+ def submodule_paths
50
+ @submodule_paths ||= {}
51
+ end
52
+
53
+ def git_submodules_command
54
+ Licensed::Shell.execute("git", "submodule", "foreach", "-q", "--recursive", "echo #{GIT_SUBMODULES_ARGUMENTS.join(" ")}")
55
+ end
56
+
57
+ def gitmodules_path
58
+ @config.pwd.join(".gitmodules")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -154,7 +154,7 @@ module Licensed
154
154
  ENV["GOPATH"]
155
155
  else
156
156
  root = begin
157
- Licensed::Git.repository_root
157
+ @config.root
158
158
  rescue Licensed::Shell::Error
159
159
  Pathname.pwd
160
160
  end
@@ -19,6 +19,7 @@ module Licensed
19
19
  def dependencies
20
20
  @dependencies ||= packages.map do |package_name, sources|
21
21
  Licensed::Source::Manifest::Dependency.new(sources,
22
+ @config.root,
22
23
  package_license(package_name),
23
24
  {
24
25
  "type" => Manifest.type,
@@ -43,7 +44,7 @@ module Licensed
43
44
  license_path = @config.dig("manifest", "licenses", package_name)
44
45
  return unless license_path
45
46
 
46
- license_path = Licensed::Git.repository_root.join(license_path)
47
+ license_path = @config.root.join(license_path)
47
48
  return unless license_path.exist?
48
49
  license_path
49
50
  end
@@ -54,7 +55,7 @@ module Licensed
54
55
  manifest.each_with_object({}) do |(src, package_name), hsh|
55
56
  next if src.nil? || src.empty?
56
57
  hsh[package_name] ||= []
57
- hsh[package_name] << File.join(Licensed::Git.repository_root, src)
58
+ hsh[package_name] << File.join(@config.root, src)
58
59
  end
59
60
  end
60
61
 
@@ -73,7 +74,7 @@ module Licensed
73
74
  # Returns the manifest location for the app
74
75
  def manifest_path
75
76
  path = @config.dig("manifest", "path")
76
- return Licensed::Git.repository_root.join(path) if path
77
+ return @config.root.join(path) if path
77
78
 
78
79
  @config.cache_path.join("manifest.json")
79
80
  end
@@ -144,7 +145,7 @@ module Licensed
144
145
  return Set.new if patterns.nil? || patterns.empty?
145
146
 
146
147
  # evaluate all patterns from the project root
147
- Dir.chdir Licensed::Git.repository_root do
148
+ Dir.chdir @config.root do
148
149
  Array(patterns).reduce(Set.new) do |files, pattern|
149
150
  if pattern.start_with?("!")
150
151
  # if the pattern is an exclusion, remove all matching files
@@ -176,9 +177,9 @@ module Licensed
176
177
  )
177
178
  /imx.freeze
178
179
 
179
- def initialize(sources, license_path, metadata = {})
180
+ def initialize(sources, root, license_path, metadata = {})
180
181
  @sources = sources
181
- license_path ||= sources_license_path(sources)
182
+ license_path ||= sources_license_path(sources, root)
182
183
  super license_path, metadata
183
184
  end
184
185
 
@@ -201,16 +202,16 @@ module Licensed
201
202
  private
202
203
 
203
204
  # Returns the top-most directory that is common to all paths in `sources`
204
- def sources_license_path(sources)
205
+ def sources_license_path(sources, root)
205
206
  # return the source directory if there is only one source given
206
207
  return source_directory(sources[0]) if sources.size == 1
207
208
 
208
209
  common_prefix = Pathname.common_prefix(*sources).to_path
209
210
 
210
- # don't allow the repo root to be used as common prefix
211
+ # don't allow the workspace root to be used as common prefix
211
212
  # the project this is run for should be excluded from the manifest,
212
213
  # or ignored in the config. any license in the root should be ignored.
213
- return common_prefix if common_prefix != Licensed::Git.repository_root
214
+ return common_prefix if common_prefix != root
214
215
 
215
216
  # use the first source directory as the license path.
216
217
  source_directory(sources.first)
@@ -17,11 +17,7 @@ module Licensed
17
17
  end
18
18
 
19
19
  def dependencies
20
- return @dependencies if defined?(@dependencies)
21
-
22
- packages = recursive_dependencies(JSON.parse(package_metadata_command)["dependencies"])
23
-
24
- @dependencies = packages.map do |name, package|
20
+ @dependencies ||= packages.map do |name, package|
25
21
  path = package["path"]
26
22
  fail "couldn't locate #{name} under node_modules/" unless path
27
23
  Dependency.new(path, {
@@ -29,16 +25,32 @@ module Licensed
29
25
  "name" => package["name"],
30
26
  "version" => package["version"],
31
27
  "summary" => package["description"],
32
- "homepage" => package["homepage"]
28
+ "homepage" => package["homepage"],
29
+ "path" => name
33
30
  })
34
31
  end
35
32
  end
36
33
 
34
+ def packages
35
+ root_dependencies = JSON.parse(package_metadata_command)["dependencies"]
36
+ recursive_dependencies(root_dependencies).each_with_object({}) do |(name, results), hsh|
37
+ results.uniq! { |package| package["version"] }
38
+ if results.size == 1
39
+ hsh[name] = results[0]
40
+ else
41
+ results.each do |package|
42
+ name_with_version = "#{name}-#{package["version"]}"
43
+ hsh[name_with_version] = package
44
+ end
45
+ end
46
+ end
47
+ end
48
+
37
49
  # Recursively parse dependency JSON data. Returns a hash mapping the
38
50
  # package name to it's metadata
39
51
  def recursive_dependencies(dependencies, result = {})
40
52
  dependencies.each do |name, dependency|
41
- (result[name] ||= {}).update(dependency)
53
+ (result[name] ||= []) << dependency
42
54
  recursive_dependencies(dependency["dependencies"] || {}, result)
43
55
  end
44
56
  result
@@ -63,7 +63,7 @@ module Licensed
63
63
  return @virtual_env_dir if defined?(@virtual_env_dir)
64
64
  @virtual_env_dir = begin
65
65
  venv_dir = @config.dig("python", "virtual_env_dir")
66
- File.expand_path(venv_dir, Licensed::Git.repository_root) if venv_dir
66
+ File.expand_path(venv_dir, @config.root) if venv_dir
67
67
  end
68
68
  end
69
69
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "1.3.4".freeze
3
+ VERSION = "1.4.0".freeze
4
4
  end
@@ -0,0 +1,39 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # setup test fixtures
5
+ BASE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
6
+ cd $BASE_PATH/test/fixtures/git_submodule
7
+
8
+ FIXTURES="$(pwd)/nested $(pwd)/submodule $(pwd)/project"
9
+ SUBMODULE=""
10
+ echo "setting up git_submodule test fixtures"
11
+ for fixture in $FIXTURES; do
12
+ if [ "$1" == "-f" ]; then
13
+ rm -rf $fixture
14
+ fi
15
+
16
+ mkdir -p $fixture
17
+ pushd $fixture >/dev/null
18
+
19
+ # fixture is already set up, use "-f" to force a refresh
20
+ if [ -e ".git" ]; then
21
+ continue
22
+ fi
23
+
24
+ git init -q .
25
+ cp $BASE_PATH/LICENSE .
26
+ git add LICENSE
27
+ git commit -q -m "init"
28
+
29
+ if [ -n "$SUBMODULE" ] ; then
30
+ git submodule add -q "$SUBMODULE" "vendor/$(basename $SUBMODULE)"
31
+ git submodule update --recursive --init -q
32
+ git add . && git commit -q -m "update submodule"
33
+ fi
34
+
35
+ echo "$(basename $fixture) created"
36
+
37
+ SUBMODULE="$(pwd)"
38
+ popd >/dev/null
39
+ done
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: 1.3.4
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-21 00:00:00.000000000 Z
11
+ date: 2018-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: licensee
@@ -176,6 +176,7 @@ files:
176
176
  - docs/sources/bundler.md
177
177
  - docs/sources/cabal.md
178
178
  - docs/sources/dep.md
179
+ - docs/sources/git_submodule.md
179
180
  - docs/sources/go.md
180
181
  - docs/sources/manifests.md
181
182
  - docs/sources/npm.md
@@ -196,6 +197,7 @@ files:
196
197
  - lib/licensed/source/bundler.rb
197
198
  - lib/licensed/source/cabal.rb
198
199
  - lib/licensed/source/dep.rb
200
+ - lib/licensed/source/git_submodule.rb
199
201
  - lib/licensed/source/go.rb
200
202
  - lib/licensed/source/manifest.rb
201
203
  - lib/licensed/source/npm.rb
@@ -214,6 +216,7 @@ files:
214
216
  - script/source-setup/bower
215
217
  - script/source-setup/bundler
216
218
  - script/source-setup/cabal
219
+ - script/source-setup/git_submodule
217
220
  - script/source-setup/go
218
221
  - script/source-setup/npm
219
222
  - script/source-setup/pip