licensed 3.9.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -36,27 +36,13 @@ module Licensed
36
36
 
37
37
  # Returns an array of dependency package import paths
38
38
  def packages
39
- dependency_packages =
40
- if go_version < Gem::Version.new("1.11.0")
41
- root_package_deps
42
- else
43
- go_list_deps
44
- end
45
-
46
39
  # don't include go std packages
47
40
  # don't include packages under the root project that aren't vendored
48
- dependency_packages
41
+ go_list_deps
49
42
  .reject { |pkg| go_std_package?(pkg) }
50
43
  .reject { |pkg| local_package?(pkg) }
51
44
  end
52
45
 
53
- # Returns non-ignored packages found from the root packages "Deps" property
54
- def root_package_deps
55
- # check for ignored packages to avoid raising errors calling `go list`
56
- # when ignored package is not found
57
- Parallel.map(Array(root_package["Deps"])) { |name| package_info(name) }
58
- end
59
-
60
46
  # Returns the list of dependencies as returned by "go list -json -deps"
61
47
  # available in go 1.11
62
48
  def go_list_deps
@@ -188,13 +174,6 @@ module Licensed
188
174
  package["ImportPath"]
189
175
  end
190
176
 
191
- # Returns a hash of information about the package with a given import path
192
- #
193
- # import_path - Go package import path
194
- def package_info(import_path)
195
- JSON.parse(package_info_command(import_path))
196
- end
197
-
198
177
  # Returns package information as a JSON string
199
178
  #
200
179
  # args - additional arguments to `go list`, e.g. Go package import path
@@ -202,11 +181,6 @@ module Licensed
202
181
  Licensed::Shell.execute("go", "list", "-e", "-json", *Array(args)).strip
203
182
  end
204
183
 
205
- # Returns the info for the package under test
206
- def root_package
207
- @root_package ||= package_info(".")
208
- end
209
-
210
184
  # Returns whether go source is found
211
185
  def go_source?
212
186
  with_configured_gopath { Licensed::Shell.success?("go", "doc") }
@@ -230,15 +204,6 @@ module Licensed
230
204
  end
231
205
  end
232
206
 
233
- # Returns the current version of go available, as a Gem::Version
234
- def go_version
235
- @go_version ||= begin
236
- full_version = Licensed::Shell.execute("go", "version").strip
237
- version_string = full_version.gsub(%r{.*go(\d+\.\d+(\.\d+)?).*}, "\\1")
238
- Gem::Version.new(version_string)
239
- end
240
- end
241
-
242
207
  private
243
208
 
244
209
  # Execute a block with ENV["GOPATH"] set to the value of #gopath.
@@ -9,53 +9,19 @@ require "fileutils"
9
9
  module Licensed
10
10
  module Sources
11
11
  class Gradle < Source
12
-
13
12
  DEFAULT_CONFIGURATIONS = ["runtime", "runtimeClasspath"].freeze
14
13
  GRADLE_LICENSES_PATH = ".gradle-licenses".freeze
15
-
14
+ GRADLE_LICENSES_CSV_NAME = "licenses.csv".freeze
16
15
  class Dependency < Licensed::Dependency
17
- GRADLE_LICENSES_CSV_NAME = "licenses.csv".freeze
18
-
19
16
  class << self
20
- # Returns a key to uniquely identify a name and version in the obtained CSV content
21
- def csv_key(name:, version:)
22
- "#{name}-#{version}"
23
- end
24
-
25
- # Loads and caches license report CSV data as a hash of :name-:version => :url pairs
26
- #
27
- # executable - The gradle executable to run to generate the license report
28
- # configurations - The gradle configurations to generate license report for
29
- #
30
- # Returns a hash of dependency identifiers to their license content URL
31
- def load_csv(path, executable, configurations)
32
- @csv ||= begin
33
- gradle_licenses_dir = File.join(path, GRADLE_LICENSES_PATH)
34
- Licensed::Sources::Gradle.gradle_command("generateLicenseReport", path: path, executable: executable, configurations: configurations)
35
- CSV.foreach(File.join(gradle_licenses_dir, GRADLE_LICENSES_CSV_NAME), headers: true).each_with_object({}) do |row, hsh|
36
- name, _, version = row["artifact"].rpartition(":")
37
- key = csv_key(name: name, version: version)
38
- hsh[key] = row["moduleLicenseUrl"]
39
- end
40
- ensure
41
- FileUtils.rm_rf(gradle_licenses_dir)
42
- end
43
- end
44
-
45
- # Returns the cached url for the given dependency
46
- def url_for(dependency)
47
- @csv[csv_key(name: dependency.name, version: dependency.version)]
48
- end
49
-
50
17
  # Cache and return the results of getting the license content.
51
18
  def retrieve_license(url)
52
19
  (@licenses ||= {})[url] ||= Net::HTTP.get(URI(url))
53
20
  end
54
21
  end
55
22
 
56
- def initialize(name:, version:, path:, executable:, configurations:, metadata: {})
57
- @configurations = configurations
58
- @executable = executable
23
+ def initialize(name:, version:, path:, url:, metadata: {})
24
+ @url = url
59
25
  super(name: name, version: version, path: path, metadata: metadata)
60
26
  end
61
27
 
@@ -68,32 +34,27 @@ module Licensed
68
34
 
69
35
  # Returns a Licensee::ProjectFiles::LicenseFile for the dependency
70
36
  def project_files
71
- self.class.load_csv(path, @executable, @configurations)
72
- url = self.class.url_for(self)
37
+ return [] if @url.nil?
73
38
 
74
- return [] if url.nil?
75
-
76
- license_data = self.class.retrieve_license(url)
77
-
78
- Array(Licensee::ProjectFiles::LicenseFile.new(license_data, { uri: url }))
39
+ license_data = self.class.retrieve_license(@url)
40
+ Array(Licensee::ProjectFiles::LicenseFile.new(license_data, { uri: @url }))
79
41
  end
80
42
  end
81
43
 
82
44
  def enabled?
83
- !gradle_executable.to_s.empty? && File.exist?(config.pwd.join("build.gradle"))
45
+ !executable.to_s.empty? && File.exist?(config.pwd.join("build.gradle"))
84
46
  end
85
47
 
86
48
  def enumerate_dependencies
87
- JSON.parse(self.class.gradle_command("printDependencies", path: config.pwd, executable: gradle_executable, configurations: configurations)).map do |package|
88
- name = "#{package["group"]}:#{package["name"]}"
49
+ JSON.parse(gradle_runner.run("printDependencies", config.source_path)).map do |package|
50
+ name = "#{package['group']}:#{package['name']}"
89
51
  Dependency.new(
90
52
  name: name,
91
53
  version: package["version"],
92
54
  path: config.pwd,
93
- executable: gradle_executable,
94
- configurations: configurations,
55
+ url: package_url(name: name, version: package["version"]),
95
56
  metadata: {
96
- "type" => Gradle.type
57
+ "type" => Gradle.type,
97
58
  }
98
59
  )
99
60
  end
@@ -101,15 +62,20 @@ module Licensed
101
62
 
102
63
  private
103
64
 
104
- def gradle_executable
105
- return @gradle_executable if defined?(@gradle_executable)
106
- @gradle_executable = begin
107
- gradlew = File.join(config.pwd, "gradlew")
65
+ def executable
66
+ return @executable if defined?(@executable)
67
+
68
+ @executable = begin
108
69
  return gradlew if File.executable?(gradlew)
70
+
109
71
  "gradle" if Licensed::Shell.tool_available?("gradle")
110
72
  end
111
73
  end
112
74
 
75
+ def gradle_runner
76
+ @gradle_runner ||= Runner.new(config.pwd, configurations, executable)
77
+ end
78
+
113
79
  # Returns the configurations to include in license generation.
114
80
  # Defaults to ["runtime", "runtimeClasspath"]
115
81
  def configurations
@@ -122,61 +88,128 @@ module Licensed
122
88
  end
123
89
  end
124
90
 
125
- def self.add_gradle_license_report_plugins_block(gradle_build_file)
126
-
127
- if gradle_build_file.include? "plugins"
128
- gradle_build_file.gsub(/(?<=plugins)\s+{/, " { id 'com.github.jk1.dependency-license-report' version '1.16'")
129
- else
130
-
131
- gradle_build_file = " plugins { id 'com.github.jk1.dependency-license-report' version '1.16' }" + gradle_build_file
91
+ # Returns the path to the Gradle wrapper.
92
+ def gradlew
93
+ @gradlew ||= begin
94
+ gradlew = config.dig("gradle", "gradlew")
95
+ config.root.join(gradlew || "gradlew").to_s
132
96
  end
133
97
  end
134
98
 
135
- def self.gradle_command(*args, path:, executable:, configurations:)
136
- gradle_build_file = File.read("build.gradle")
99
+ # Returns a key to uniquely identify a name and version in the obtained CSV content
100
+ def csv_key(name:, version:)
101
+ "#{name}-#{version}"
102
+ end
103
+
104
+ def package_url(name:, version:)
105
+ # load and memoize the license report CSV
106
+ @urls ||= load_csv
137
107
 
138
- if !gradle_build_file.include? "dependency-license-report"
139
- gradle_build_file = Licensed::Sources::Gradle.add_gradle_license_report_plugins_block(gradle_build_file)
140
- end
108
+ # uniquely identify a name and version in the obtained CSV content
109
+ @urls["#{name}-#{version}"]
110
+ end
141
111
 
142
- Dir.chdir(path) do
143
- Tempfile.create(["license-", ".gradle"], path) do |f|
144
- f.write(gradle_build_file)
145
- f.write gradle_file(configurations)
146
- f.close
147
- Licensed::Shell.execute(executable, "-q", "-b", f.path, *args)
112
+ def load_csv
113
+ begin
114
+ # create the CSV file including dependency license urls using the gradle plugin
115
+ gradle_licenses_dir = File.join(config.root, GRADLE_LICENSES_PATH)
116
+ gradle_runner.run("generateLicenseReport", config.source_path)
117
+
118
+ # parse the CSV report for dependency license urls
119
+ CSV.foreach(File.join(gradle_licenses_dir, GRADLE_LICENSES_CSV_NAME), headers: true).each_with_object({}) do |row, hsh|
120
+ name, _, version = row["artifact"].rpartition(":")
121
+ key = csv_key(name: name, version: version)
122
+ hsh[key] = row["moduleLicenseUrl"]
148
123
  end
124
+ ensure
125
+ FileUtils.rm_rf(gradle_licenses_dir)
149
126
  end
150
127
  end
151
128
 
152
- def self.gradle_file(configurations)
153
- <<~EOF
129
+ # Returns the cached url for the given dependency
130
+ def url_for(dependency)
131
+ @csv[csv_key(name: dependency.name, version: dependency.version)]
132
+ end
133
+
134
+ # The Gradle::Runner class is a wrapper which provides
135
+ # an interface to run gradle commands with the init script initialized
136
+ class Runner
137
+ def initialize(root_path, configurations, executable)
138
+ @root_path = root_path
139
+ @executable = executable
140
+ @init_script = create_init_script(root_path, configurations)
141
+ end
154
142
 
155
- import com.github.jk1.license.render.CsvReportRenderer
156
- import com.github.jk1.license.filter.LicenseBundleNormalizer
143
+ def run(command, source_path)
144
+ args = [format_command(command, source_path)]
145
+ # The configuration cache is an incubating feature that can be activated manually.
146
+ # The gradle plugin for licenses does not support it so we prevent it to run for gradle version supporting it.
147
+ args << "--no-configuration-cache" if gradle_version >= "6.6"
148
+ Licensed::Shell.execute(@executable, "-q", "--init-script", @init_script.path, *args)
149
+ end
157
150
 
158
- final configs = #{configurations.inspect}
151
+ private
159
152
 
160
- licenseReport {
161
- configurations = configs
162
- outputDir = "$projectDir/#{GRADLE_LICENSES_PATH}"
163
- renderers = [new CsvReportRenderer()]
164
- filters = [new LicenseBundleNormalizer()]
165
- }
153
+ def gradle_version
154
+ @gradle_version ||= Licensed::Shell.execute(@executable, "--version").scan(/Gradle [\d+]\.[\d+]/).last.split(" ").last
155
+ end
166
156
 
167
- task printDependencies {
168
- doLast {
169
- def dependencies = []
170
- configs.each {
171
- configurations[it].resolvedConfiguration.resolvedArtifacts.each { artifact ->
172
- def id = artifact.moduleVersion.id
173
- dependencies << " { \\"group\\": \\"${id.group}\\", \\"name\\": \\"${id.name}\\", \\"version\\": \\"${id.version}\\" }"
157
+ def create_init_script(path, configurations)
158
+ Dir.chdir(path) do
159
+ f = Tempfile.new(["init", ".gradle"], @root_path)
160
+ f.write(
161
+ <<~EOF
162
+ import com.github.jk1.license.render.CsvReportRenderer
163
+ import com.github.jk1.license.filter.LicenseBundleNormalizer
164
+ final configs = #{configurations.inspect}
165
+
166
+ initscript {
167
+ repositories {
168
+ maven {
169
+ url "https://plugins.gradle.org/m2/"
174
170
  }
171
+ }
172
+ dependencies {
173
+ classpath "com.github.jk1:gradle-license-report:#{gradle_version >= "7.0" ? "2.0" : "1.17"}"
174
+ }
175
175
  }
176
- println "[\\n${dependencies.join(", ")}\\n]"
177
- }
178
- }
179
- EOF
176
+
177
+ allprojects {
178
+ apply plugin: com.github.jk1.license.LicenseReportPlugin
179
+ licenseReport {
180
+ outputDir = "$rootDir/.gradle-licenses"
181
+ configurations = configs
182
+ renderers = [new CsvReportRenderer()]
183
+ filters = [new LicenseBundleNormalizer()]
184
+ }
185
+
186
+ task printDependencies {
187
+ doLast {
188
+ def dependencies = []
189
+ configs.each {
190
+ configurations[it].resolvedConfiguration.resolvedArtifacts.each { artifact ->
191
+ def id = artifact.moduleVersion.id
192
+ dependencies << "{ \\"group\\": \\"${id.group}\\", \\"name\\": \\"${id.name}\\", \\"version\\": \\"${id.version}\\" }"
193
+ }
194
+ }
195
+ println "[${dependencies.join(", ")}]"
196
+ }
197
+ }
198
+ }
199
+ EOF
200
+ )
201
+ f.close
202
+ f
203
+ end
204
+ end
205
+
206
+ # Prefixes the gradle command with the project name for multi-build projects.
207
+ def format_command(command, source_path)
208
+ Dir.chdir(source_path) do
209
+ path = Licensed::Shell.execute(@executable, "properties", "-Dorg.gradle.logging.level=quiet").scan(/path:.*/).last.split(" ").last
210
+ path == ":" ? command : "#{path}:#{command}"
211
+ end
212
+ end
180
213
  end
181
214
  end
182
215
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ require "json"
3
+
4
+ module Licensed
5
+ module Sources
6
+ class PNPM < Source
7
+ # Returns true when pnpm is installed and a pnpm-lock.yaml file is found,
8
+ # otherwise false
9
+ def enabled?
10
+ return false unless Licensed::Shell.tool_available?("pnpm")
11
+ File.exist?(File.join(config.pwd, "pnpm-lock.yaml"))
12
+ end
13
+
14
+ def enumerate_dependencies
15
+ packages.map do |package|
16
+ name_with_version = "#{package["name"]}@#{package["version"]}"
17
+ Dependency.new(
18
+ name: name_with_version,
19
+ version: package["version"],
20
+ path: package["path"],
21
+ metadata: {
22
+ "type" => PNPM.type,
23
+ "name" => package["name"],
24
+ "summary" => package["description"],
25
+ "homepage" => package["homepage"]
26
+ }
27
+ )
28
+ end
29
+ end
30
+
31
+ # Returns package metadata returned from `pnpm licensed list`
32
+ def packages
33
+ JSON.parse(package_metadata_command).values.flatten
34
+ rescue JSON::ParserError => e
35
+ message = "Licensed was unable to parse the output from 'pnpm licenses list'. JSON Error: #{e.message}"
36
+ raise Licensed::Sources::Source::Error, message
37
+ end
38
+
39
+ # Returns the output from running `pnpm licenses list` to get package metadata
40
+ def package_metadata_command
41
+ args = %w(--json --long)
42
+ args << "--prod" unless include_non_production?
43
+ Licensed::Shell.execute("pnpm", "licenses", "list", *args, allow_failure: true)
44
+ end
45
+
46
+ # Returns whether to include non production dependencies based on the licensed configuration settings
47
+ def include_non_production?
48
+ config.dig("pnpm", "production_only") == false
49
+ end
50
+ end
51
+ end
52
+ end
@@ -69,7 +69,9 @@ module Licensed
69
69
  # Returns all dependencies that should be evaluated.
70
70
  # Excludes ignored dependencies.
71
71
  def dependencies
72
- cached_dependencies.reject { |d| ignored?(d) }
72
+ cached_dependencies
73
+ .reject { |d| ignored?(d) }
74
+ .each { |d| add_additional_terms_from_configuration(d) }
73
75
  end
74
76
 
75
77
  # Enumerate all source dependencies. Must be implemented by each source class.
@@ -88,6 +90,11 @@ module Licensed
88
90
  def cached_dependencies
89
91
  @dependencies ||= enumerate_dependencies.compact
90
92
  end
93
+
94
+ # Add any additional_terms for this dependency that have been added to the configuration
95
+ def add_additional_terms_from_configuration(dependency)
96
+ dependency.additional_terms.concat config.additional_terms_for_dependency("type" => self.class.type, "name" => dependency.name)
97
+ end
91
98
  end
92
99
  end
93
100
  end
@@ -6,18 +6,20 @@ module Licensed
6
6
  require "licensed/sources/bundler"
7
7
  require "licensed/sources/cabal"
8
8
  require "licensed/sources/cargo"
9
+ require "licensed/sources/cocoapods"
9
10
  require "licensed/sources/composer"
10
11
  require "licensed/sources/dep"
11
12
  require "licensed/sources/git_submodule"
12
13
  require "licensed/sources/go"
14
+ require "licensed/sources/gradle"
13
15
  require "licensed/sources/manifest"
16
+ require "licensed/sources/mix"
14
17
  require "licensed/sources/npm"
15
18
  require "licensed/sources/nuget"
16
19
  require "licensed/sources/pip"
17
20
  require "licensed/sources/pipenv"
21
+ require "licensed/sources/pnpm"
18
22
  require "licensed/sources/swift"
19
- require "licensed/sources/gradle"
20
- require "licensed/sources/mix"
21
23
  require "licensed/sources/yarn"
22
24
  end
23
25
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Licensed
3
- VERSION = "3.9.1".freeze
3
+ VERSION = "4.1.0".freeze
4
4
 
5
5
  def self.previous_major_versions
6
6
  major_version = Gem::Version.new(Licensed::VERSION).segments.first
data/licensed.gemspec CHANGED
@@ -21,21 +21,21 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.required_ruby_version = ">= 2.3.0"
24
+ spec.required_ruby_version = ">= 2.6.0"
25
25
 
26
- spec.add_dependency "licensee", ">= 9.15.2", "< 10.0.0"
27
- spec.add_dependency "thor", ">= 0.19"
26
+ spec.add_dependency "licensee", "~> 9.16"
27
+ spec.add_dependency "thor", "~> 1.2"
28
28
  spec.add_dependency "pathname-common_prefix", "~> 0.0.1"
29
- spec.add_dependency "tomlrb", ">= 1.2", "< 3.0"
30
- spec.add_dependency "bundler", ">= 1.10"
31
- spec.add_dependency "ruby-xxHash", "~> 0.4"
32
- spec.add_dependency "parallel", ">= 0.18.0"
33
- spec.add_dependency "reverse_markdown", ">= 1", "< 3"
34
- spec.add_dependency "json", ">= 2.6.2"
29
+ spec.add_dependency "tomlrb", "~> 2.0"
30
+ spec.add_dependency "ruby-xxHash", "~> 0.4.0"
31
+ spec.add_dependency "parallel", "~> 1.22"
32
+ spec.add_dependency "reverse_markdown", "~> 2.1"
33
+ spec.add_dependency "json", "~> 2.6"
34
+ # spec.add_dependency "cocoapods-core", "~> 1.11"
35
35
 
36
- spec.add_development_dependency "rake", ">= 12.3.3"
37
- spec.add_development_dependency "minitest", "~> 5.8"
36
+ spec.add_development_dependency "rake", "~> 13.0"
37
+ spec.add_development_dependency "minitest", "~> 5.17"
38
38
  spec.add_development_dependency "mocha", "~> 2.0"
39
- spec.add_development_dependency "rubocop-github", "~> 0.6"
40
- spec.add_development_dependency "byebug", "~> 11.1.3"
39
+ spec.add_development_dependency "rubocop-github", "~> 0.20"
40
+ spec.add_development_dependency "byebug", "~> 11.1"
41
41
  end