licensed 2.15.2 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +55 -11
- data/CHANGELOG.md +56 -1
- data/README.md +38 -81
- data/docs/adding_a_new_source.md +11 -8
- data/docs/commands/README.md +59 -0
- data/docs/commands/cache.md +35 -0
- data/docs/commands/env.md +10 -0
- data/docs/commands/list.md +23 -0
- data/docs/commands/migrate.md +10 -0
- data/docs/commands/notices.md +12 -0
- data/docs/commands/status.md +73 -0
- data/docs/commands/version.md +3 -0
- data/docs/configuration.md +9 -161
- data/docs/configuration/README.md +11 -0
- data/docs/configuration/allowed_licenses.md +17 -0
- data/docs/configuration/application_name.md +63 -0
- data/docs/configuration/application_source.md +64 -0
- data/docs/configuration/configuration_root.md +27 -0
- data/docs/configuration/configuring_multiple_apps.md +58 -0
- data/docs/configuration/dependency_source_enumerators.md +28 -0
- data/docs/configuration/ignoring_dependencies.md +19 -0
- data/docs/configuration/metadata_cache.md +106 -0
- data/docs/configuration/reviewing_dependencies.md +18 -0
- data/docs/{migrating_to_newer_versions.md → migrations/v2.md} +1 -1
- data/docs/migrations/v3.md +109 -0
- data/docs/sources/bundler.md +1 -11
- data/docs/sources/swift.md +4 -0
- data/lib/licensed.rb +1 -0
- data/lib/licensed/cli.rb +6 -3
- data/lib/licensed/commands/cache.rb +19 -20
- data/lib/licensed/commands/command.rb +104 -72
- data/lib/licensed/commands/environment.rb +12 -11
- data/lib/licensed/commands/list.rb +0 -19
- data/lib/licensed/commands/notices.rb +0 -19
- data/lib/licensed/commands/status.rb +13 -15
- data/lib/licensed/configuration.rb +105 -12
- data/lib/licensed/report.rb +44 -0
- data/lib/licensed/reporters/cache_reporter.rb +48 -64
- data/lib/licensed/reporters/json_reporter.rb +19 -21
- data/lib/licensed/reporters/list_reporter.rb +45 -58
- data/lib/licensed/reporters/notices_reporter.rb +33 -46
- data/lib/licensed/reporters/reporter.rb +37 -104
- data/lib/licensed/reporters/status_reporter.rb +58 -56
- data/lib/licensed/reporters/yaml_reporter.rb +19 -21
- data/lib/licensed/sources.rb +1 -0
- data/lib/licensed/sources/bundler.rb +36 -217
- data/lib/licensed/sources/bundler/missing_specification.rb +54 -0
- data/lib/licensed/sources/go.rb +1 -1
- data/lib/licensed/sources/gradle.rb +2 -2
- data/lib/licensed/sources/npm.rb +4 -3
- data/lib/licensed/sources/nuget.rb +57 -27
- data/lib/licensed/sources/swift.rb +69 -0
- data/lib/licensed/version.rb +1 -1
- data/script/source-setup/go +1 -1
- data/script/source-setup/swift +22 -0
- metadata +27 -4
- data/docs/commands.md +0 -95
@@ -2,31 +2,29 @@
|
|
2
2
|
module Licensed
|
3
3
|
module Reporters
|
4
4
|
class YamlReporter < Reporter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
result
|
13
|
-
end
|
5
|
+
# Report all information from the command run to the shell as a YAML object
|
6
|
+
#
|
7
|
+
# command - The command being run
|
8
|
+
# report - A report object containing information about the command run
|
9
|
+
def end_report_command(command, report)
|
10
|
+
report["apps"] = report.reports.map(&:to_h) if report.reports.any?
|
11
|
+
shell.info sanitize(report.to_h).to_yaml
|
14
12
|
end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
# Add source report information to the app report hash
|
15
|
+
#
|
16
|
+
# app - An application configuration
|
17
|
+
# report - A report object containing information about the app evaluation
|
18
|
+
def end_report_app(app, report)
|
19
|
+
report["sources"] = report.reports.map(&:to_h) if report.reports.any?
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
# Add dependency report information to the source report hash
|
23
|
+
#
|
24
|
+
# source - A dependency source enumerator
|
25
|
+
# report - A report object containing information about the source evaluation
|
26
|
+
def end_report_source(source, report)
|
27
|
+
report["dependencies"] = report.reports.map(&:to_h) if report.reports.any?
|
30
28
|
end
|
31
29
|
|
32
30
|
def sanitize(object)
|
data/lib/licensed/sources.rb
CHANGED
@@ -14,6 +14,7 @@ module Licensed
|
|
14
14
|
require "licensed/sources/nuget"
|
15
15
|
require "licensed/sources/pip"
|
16
16
|
require "licensed/sources/pipenv"
|
17
|
+
require "licensed/sources/swift"
|
17
18
|
require "licensed/sources/gradle"
|
18
19
|
require "licensed/sources/mix"
|
19
20
|
require "licensed/sources/yarn"
|
@@ -2,50 +2,13 @@
|
|
2
2
|
require "delegate"
|
3
3
|
begin
|
4
4
|
require "bundler"
|
5
|
+
require "licensed/sources/bundler/missing_specification"
|
5
6
|
rescue LoadError
|
6
7
|
end
|
7
8
|
|
8
9
|
module Licensed
|
9
10
|
module Sources
|
10
11
|
class Bundler < Source
|
11
|
-
class MissingSpecification < Gem::BasicSpecification
|
12
|
-
attr_reader :name, :requirement
|
13
|
-
alias_method :version, :requirement
|
14
|
-
def initialize(name:, requirement:)
|
15
|
-
@name = name
|
16
|
-
@requirement = requirement
|
17
|
-
end
|
18
|
-
|
19
|
-
def dependencies
|
20
|
-
[]
|
21
|
-
end
|
22
|
-
|
23
|
-
def source
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
def platform; end
|
28
|
-
def gem_dir; end
|
29
|
-
def gems_dir
|
30
|
-
Gem.dir
|
31
|
-
end
|
32
|
-
def summary; end
|
33
|
-
def homepage; end
|
34
|
-
|
35
|
-
def error
|
36
|
-
"could not find #{name} (#{requirement}) in any sources"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class BundlerSpecification < ::SimpleDelegator
|
41
|
-
def gem_dir
|
42
|
-
dir = super
|
43
|
-
return dir if File.exist?(dir)
|
44
|
-
|
45
|
-
File.join(Gem.dir, "gems", full_name)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
12
|
class Dependency < Licensed::Dependency
|
50
13
|
attr_reader :loaded_from
|
51
14
|
|
@@ -66,7 +29,7 @@ module Licensed
|
|
66
29
|
# `loaded_from` if available.
|
67
30
|
def spec_file
|
68
31
|
return @spec_file if defined?(@spec_file)
|
69
|
-
return @spec_file = nil unless loaded_from && File.
|
32
|
+
return @spec_file = nil unless loaded_from && File.file?(loaded_from)
|
70
33
|
@spec_file = begin
|
71
34
|
file = { name: File.basename(loaded_from), dir: File.dirname(loaded_from) }
|
72
35
|
Licensee::ProjectFiles::PackageManagerFile.new(File.read(loaded_from), file)
|
@@ -76,6 +39,7 @@ module Licensed
|
|
76
39
|
|
77
40
|
GEMFILES = { "Gemfile" => "Gemfile.lock", "gems.rb" => "gems.locked" }
|
78
41
|
DEFAULT_WITHOUT_GROUPS = %i{development test}
|
42
|
+
RUBY_PACKER_ERROR = "The bundler source cannot be used from the executable built with ruby-packer. Please install licensed using `gem install` or using bundler."
|
79
43
|
|
80
44
|
def enabled?
|
81
45
|
# running a ruby-packer-built licensed exe when ruby isn't available
|
@@ -85,13 +49,18 @@ module Licensed
|
|
85
49
|
end
|
86
50
|
|
87
51
|
def enumerate_dependencies
|
52
|
+
raise Licensed::Sources::Source::Error.new(RUBY_PACKER_ERROR) if ruby_packer?
|
53
|
+
|
88
54
|
with_local_configuration do
|
89
55
|
specs.map do |spec|
|
56
|
+
next if spec.name == "bundler" && !include_bundler?
|
57
|
+
next if spec.name == config["name"]
|
58
|
+
|
90
59
|
error = spec.error if spec.respond_to?(:error)
|
91
60
|
Dependency.new(
|
92
61
|
name: spec.name,
|
93
62
|
version: spec.version.to_s,
|
94
|
-
path: spec.
|
63
|
+
path: spec.full_gem_path,
|
95
64
|
loaded_from: spec.loaded_from,
|
96
65
|
errors: Array(error),
|
97
66
|
metadata: {
|
@@ -106,136 +75,18 @@ module Licensed
|
|
106
75
|
|
107
76
|
# Returns an array of Gem::Specifications for all gem dependencies
|
108
77
|
def specs
|
109
|
-
|
110
|
-
root_dependencies = definition.dependencies.select { |d| include?(d, nil) }
|
111
|
-
root_specs = specs_for_dependencies(root_dependencies, nil).compact
|
112
|
-
|
113
|
-
# recursively find the remaining specifications
|
114
|
-
all_specs = recursive_specs(root_specs)
|
115
|
-
|
116
|
-
# delete any specifications loaded from a gemspec
|
117
|
-
all_specs.delete_if { |s| s.source.is_a?(::Bundler::Source::Gemspec) }
|
118
|
-
end
|
119
|
-
|
120
|
-
# Recursively finds the dependencies for Gem specifications.
|
121
|
-
# Returns a `Set` containing the package names for all dependencies
|
122
|
-
def recursive_specs(specs, results = Set.new)
|
123
|
-
return [] if specs.nil? || specs.empty?
|
124
|
-
|
125
|
-
new_specs = Set.new(specs) - results.to_a
|
126
|
-
return [] if new_specs.empty?
|
127
|
-
|
128
|
-
results.merge new_specs
|
129
|
-
|
130
|
-
dependency_specs = new_specs.flat_map { |s| specs_for_dependencies(s.dependencies, s.source) }
|
131
|
-
|
132
|
-
return results if dependency_specs.empty?
|
133
|
-
|
134
|
-
results.merge recursive_specs(dependency_specs, results)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Returns the specs for dependencies that pass the checks in `include?`.
|
138
|
-
# Returns a `MissingSpecification` if a gem specification isn't found.
|
139
|
-
def specs_for_dependencies(dependencies, source)
|
140
|
-
included_dependencies = dependencies.select { |d| include?(d, source) }
|
141
|
-
included_dependencies.map do |dep|
|
142
|
-
gem_spec(dep) || MissingSpecification.new(name: dep.name, requirement: dep.requirement)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# Returns a Gem::Specification for the provided gem argument.
|
147
|
-
def gem_spec(dependency)
|
148
|
-
return unless dependency
|
149
|
-
|
150
|
-
# find a specifiction from the resolved ::Bundler::Definition specs
|
151
|
-
spec = definition.resolve.find { |s| s.satisfies?(dependency) }
|
152
|
-
|
153
|
-
# a nil spec should be rare, generally only seen from bundler
|
154
|
-
return matching_spec(dependency) || bundle_exec_gem_spec(dependency.name, dependency.requirement) if spec.nil?
|
155
|
-
|
156
|
-
# try to find a non-lazy specification that matches `spec`
|
157
|
-
# spec.source.specs gives access to specifications with more
|
158
|
-
# information than spec itself, including platform-specific gems.
|
159
|
-
# these objects should have all the information needed to detect license metadata
|
160
|
-
source_spec = spec.source.specs.find { |s| s.name == spec.name && s.version == spec.version }
|
161
|
-
return source_spec if source_spec
|
162
|
-
|
163
|
-
# look for a specification at the bundler specs path
|
164
|
-
spec_path = ::Bundler.specs_path.join("#{spec.full_name}.gemspec")
|
165
|
-
return Gem::Specification.load(spec_path.to_s) if File.exist?(spec_path.to_s)
|
166
|
-
|
167
|
-
# if the specification file doesn't exist, get the specification using
|
168
|
-
# the bundler and gem CLI
|
169
|
-
bundle_exec_gem_spec(dependency.name, dependency.requirement)
|
170
|
-
end
|
171
|
-
|
172
|
-
# Returns whether a dependency should be included in the final
|
173
|
-
def include?(dependency, source)
|
174
|
-
# ::Bundler::Dependency has an extra `should_include?`
|
175
|
-
return false unless dependency.should_include? if dependency.respond_to?(:should_include?)
|
176
|
-
|
177
|
-
# Don't return gems added from `add_development_dependency` in a gemspec
|
178
|
-
# if the :development group is excluded
|
179
|
-
gemspec_source = source.is_a?(::Bundler::Source::Gemspec)
|
180
|
-
return false if dependency.type == :development && (!gemspec_source || exclude_development_dependencies?)
|
181
|
-
|
182
|
-
# Gem::Dependency don't have groups - in our usage these objects always
|
183
|
-
# come as child-dependencies and are never directly from a Gemfile.
|
184
|
-
# We assume that all Gem::Dependencies are ok at this point
|
185
|
-
return true if dependency.groups.nil?
|
186
|
-
|
187
|
-
# check if the dependency is in any groups we're interested in
|
188
|
-
(dependency.groups & groups).any?
|
189
|
-
end
|
190
|
-
|
191
|
-
# Returns whether development dependencies should be excluded
|
192
|
-
def exclude_development_dependencies?
|
193
|
-
@include_development ||= begin
|
194
|
-
# check whether the development dependency group is explicitly removed
|
195
|
-
# or added via bundler and licensed configurations
|
196
|
-
groups = [:development] - Array(::Bundler.settings[:without]) + Array(::Bundler.settings[:with]) - exclude_groups
|
197
|
-
!groups.include?(:development)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Load a gem specification from the YAML returned from `gem specification`
|
202
|
-
# This is a last resort when licensed can't obtain a specification from other means
|
203
|
-
def bundle_exec_gem_spec(name, requirement)
|
204
|
-
# `gem` must be available to run `gem specification`
|
205
|
-
return unless Licensed::Shell.tool_available?("gem")
|
206
|
-
|
207
|
-
# use `gem specification` with a clean ENV and clean Gem.dir paths
|
208
|
-
# to get gem specification at the right directory
|
209
|
-
begin
|
210
|
-
::Bundler.with_original_env do
|
211
|
-
::Bundler.rubygems.clear_paths
|
212
|
-
yaml = Licensed::Shell.execute(*ruby_command_args("gem", "specification", name, "-v", requirement.to_s))
|
213
|
-
spec = Gem::Specification.from_yaml(yaml)
|
214
|
-
# this is horrible, but it will cache the gem_dir using the clean env
|
215
|
-
# so that it can be used outside of this block when running from
|
216
|
-
# the ruby packer executable environment
|
217
|
-
spec.gem_dir if ruby_packer?
|
218
|
-
spec
|
219
|
-
end
|
220
|
-
rescue Licensed::Shell::Error
|
221
|
-
# return nil
|
222
|
-
ensure
|
223
|
-
::Bundler.configure
|
224
|
-
end
|
78
|
+
@specs ||= definition.specs_for(groups)
|
225
79
|
end
|
226
80
|
|
227
|
-
#
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
237
|
-
ensure
|
238
|
-
::Bundler.configure
|
81
|
+
# Returns whether to include bundler as a listed dependency of the project
|
82
|
+
def include_bundler?
|
83
|
+
@include_bundler ||= begin
|
84
|
+
# include if bundler is listed as a direct dependency that should be included
|
85
|
+
requested_dependencies = definition.dependencies.select { |d| (d.groups & groups).any? && d.should_include? }
|
86
|
+
return true if requested_dependencies.any? { |d| d.name == "bundler" }
|
87
|
+
# include if bundler is an indirect dependency
|
88
|
+
return true if specs.flat_map(&:dependencies).any? { |d| d.name == "bundler" }
|
89
|
+
false
|
239
90
|
end
|
240
91
|
end
|
241
92
|
|
@@ -283,71 +134,39 @@ module Licensed
|
|
283
134
|
@lockfile_path ||= gemfile_path.dirname.join(GEMFILES[gemfile_path.basename.to_s])
|
284
135
|
end
|
285
136
|
|
286
|
-
# Returns the configured bundler executable to use, or "bundle" by default.
|
287
|
-
def bundler_exe
|
288
|
-
@bundler_exe ||= begin
|
289
|
-
exe = config.dig("bundler", "bundler_exe")
|
290
|
-
return "bundle" unless exe
|
291
|
-
return exe if Licensed::Shell.tool_available?(exe)
|
292
|
-
config.root.join(exe)
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
# Determines if the configured bundler executable is available and returns
|
297
|
-
# shell command args with or without `bundle exec` depending on availability.
|
298
|
-
def ruby_command_args(*args)
|
299
|
-
return Array(args) unless Licensed::Shell.tool_available?(bundler_exe)
|
300
|
-
[bundler_exe, "exec", *args]
|
301
|
-
end
|
302
|
-
|
303
|
-
private
|
304
|
-
|
305
137
|
# helper to clear all bundler environment around a yielded block
|
306
138
|
def with_local_configuration
|
307
|
-
#
|
308
|
-
|
139
|
+
# silence any bundler warnings while running licensed
|
140
|
+
bundler_ui, ::Bundler.ui = ::Bundler.ui, ::Bundler::UI::Silent.new
|
309
141
|
|
310
|
-
|
311
|
-
|
142
|
+
original_bundle_gemfile = nil
|
143
|
+
if gemfile_path.to_s != ENV["BUNDLE_GEMFILE"]
|
144
|
+
# force bundler to use the local gem file
|
145
|
+
original_bundle_gemfile, ENV["BUNDLE_GEMFILE"] = ENV["BUNDLE_GEMFILE"], gemfile_path.to_s
|
312
146
|
|
313
|
-
#
|
314
|
-
|
315
|
-
#
|
316
|
-
|
317
|
-
ruby_version = Gem::ConfigMap[:ruby_version]
|
318
|
-
# set the ruby version in Gem::ConfigMap to the ruby version from the host.
|
319
|
-
# this helps Bundler find the correct spec sources and paths
|
320
|
-
Gem::ConfigMap[:ruby_version] = host_ruby_version
|
147
|
+
# reset all bundler configuration
|
148
|
+
::Bundler.reset!
|
149
|
+
# and re-configure with settings for current directory
|
150
|
+
::Bundler.configure
|
321
151
|
end
|
322
152
|
|
323
|
-
# reset all bundler configuration
|
324
|
-
::Bundler.reset!
|
325
|
-
# and re-configure with settings for current directory
|
326
|
-
::Bundler.configure
|
327
|
-
|
328
153
|
yield
|
329
154
|
ensure
|
330
|
-
if
|
331
|
-
|
332
|
-
|
333
|
-
|
155
|
+
if original_bundle_gemfile
|
156
|
+
ENV["BUNDLE_GEMFILE"] = original_bundle_gemfile
|
157
|
+
|
158
|
+
# restore bundler configuration
|
159
|
+
::Bundler.reset!
|
160
|
+
::Bundler.configure
|
334
161
|
end
|
335
162
|
|
336
|
-
|
337
|
-
# restore bundler configuration
|
338
|
-
::Bundler.reset!
|
339
|
-
::Bundler.configure
|
163
|
+
::Bundler.ui = bundler_ui
|
340
164
|
end
|
341
165
|
|
342
166
|
# Returns whether the current licensed execution is running ruby-packer
|
343
167
|
def ruby_packer?
|
344
168
|
@ruby_packer ||= RbConfig::TOPDIR =~ /__enclose_io_memfs__/
|
345
169
|
end
|
346
|
-
|
347
|
-
# Returns the ruby version found in the bundler environment
|
348
|
-
def host_ruby_version
|
349
|
-
Licensed::Shell.execute(*ruby_command_args("ruby", "-e", "puts Gem::ConfigMap[:ruby_version]"))
|
350
|
-
end
|
351
170
|
end
|
352
171
|
end
|
353
172
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/match_platform"
|
4
|
+
|
5
|
+
# Bundler normally raises a "GemNotFound" error when a specification
|
6
|
+
# can't be materialized which halts bundler dependency enumeration.
|
7
|
+
|
8
|
+
# This monkey patch instead creates MissingSpecification objects to
|
9
|
+
# identify missing specs without raising errors and halting enumeration.
|
10
|
+
# It was the most minimal-touch solution I could think of that should reliably
|
11
|
+
# work across many bundler versions
|
12
|
+
|
13
|
+
module Licensed
|
14
|
+
module Bundler
|
15
|
+
class MissingSpecification < Gem::BasicSpecification
|
16
|
+
include ::Bundler::MatchPlatform
|
17
|
+
|
18
|
+
attr_reader :name, :version, :platform, :source
|
19
|
+
def initialize(name:, version:, platform:, source:)
|
20
|
+
@name = name
|
21
|
+
@version = version
|
22
|
+
@platform = platform
|
23
|
+
@source = source
|
24
|
+
end
|
25
|
+
|
26
|
+
def dependencies
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def gem_dir; end
|
31
|
+
def gems_dir
|
32
|
+
Gem.dir
|
33
|
+
end
|
34
|
+
def summary; end
|
35
|
+
def homepage; end
|
36
|
+
|
37
|
+
def error
|
38
|
+
"could not find #{name} (#{version}) in any sources"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Bundler
|
45
|
+
class LazySpecification
|
46
|
+
alias_method :orig_materialize, :__materialize__
|
47
|
+
def __materialize__
|
48
|
+
spec = orig_materialize
|
49
|
+
return spec if spec
|
50
|
+
|
51
|
+
Licensed::Bundler::MissingSpecification.new(name: name, version: version, platform: platform, source: source)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/licensed/sources/go.rb
CHANGED
@@ -98,7 +98,7 @@ module Licensed
|
|
98
98
|
# Returns whether the package is local to the current project
|
99
99
|
def local_package?(package)
|
100
100
|
return false unless package && package["Dir"]
|
101
|
-
return false unless File.fnmatch?("#{config.root.to_s}*", package["Dir"])
|
101
|
+
return false unless File.fnmatch?("#{config.root.to_s}*", package["Dir"], File::FNM_CASEFOLD)
|
102
102
|
vendored_path_parts(package).nil?
|
103
103
|
end
|
104
104
|
|
@@ -125,10 +125,10 @@ module Licensed
|
|
125
125
|
def self.add_gradle_license_report_plugins_block(gradle_build_file)
|
126
126
|
|
127
127
|
if gradle_build_file.include? "plugins"
|
128
|
-
gradle_build_file.gsub(/(?<=plugins)\s+{/, " { id 'com.github.jk1.dependency-license-report' version '1.
|
128
|
+
gradle_build_file.gsub(/(?<=plugins)\s+{/, " { id 'com.github.jk1.dependency-license-report' version '1.16'")
|
129
129
|
else
|
130
130
|
|
131
|
-
gradle_build_file = " plugins { id 'com.github.jk1.dependency-license-report' version '1.
|
131
|
+
gradle_build_file = " plugins { id 'com.github.jk1.dependency-license-report' version '1.16' }" + gradle_build_file
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|