diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3910817c..8d208036 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -193,7 +193,7 @@ jobs: # are resolved, update this matrix list with '16'. # possibly fixed by https://github.com/jk1/Gradle-License-Report/pull/166 java: [ '11' ] - gradle: ['current', '6.4'] + gradle: ['current', '7.6', '6.9.3'] steps: - uses: actions/checkout@v3 - name: Set up Ruby diff --git a/lib/licensed/sources/gradle.rb b/lib/licensed/sources/gradle.rb index 63ee152a..bb942da8 100644 --- a/lib/licensed/sources/gradle.rb +++ b/lib/licensed/sources/gradle.rb @@ -9,7 +9,7 @@ module Licensed module Sources class Gradle < Source - DEFAULT_CONFIGURATIONS = ["runtime", "runtimeClasspath"].freeze + DEFAULT_CONFIGURATIONS = ["runtimeOnly", "runtimeClasspath"].freeze GRADLE_LICENSES_PATH = ".gradle-licenses".freeze GRADLE_LICENSES_CSV_NAME = "licenses.csv".freeze class Dependency < Licensed::Dependency @@ -46,7 +46,7 @@ def enabled? end def enumerate_dependencies - JSON.parse(gradle_runner.run("printDependencies", config.source_path)).map do |package| + JSON.parse(gradle_runner.run("printDependencies")).map do |package| name = "#{package['group']}:#{package['name']}" Dependency.new( name: name, @@ -73,7 +73,7 @@ def executable end def gradle_runner - @gradle_runner ||= Runner.new(config.pwd, configurations, executable) + @gradle_runner ||= Runner.new(configurations, executable) end # Returns the configurations to include in license generation. @@ -113,7 +113,7 @@ def load_csv begin # create the CSV file including dependency license urls using the gradle plugin gradle_licenses_dir = File.join(config.root, GRADLE_LICENSES_PATH) - gradle_runner.run("generateLicenseReport", config.source_path) + gradle_runner.run("generateLicenseReport") # parse the CSV report for dependency license urls CSV.foreach(File.join(gradle_licenses_dir, GRADLE_LICENSES_CSV_NAME), headers: true).each_with_object({}) do |row, hsh| @@ -134,80 +134,82 @@ def url_for(dependency) # The Gradle::Runner class is a wrapper which provides # an interface to run gradle commands with the init script initialized class Runner - def initialize(root_path, configurations, executable) - @root_path = root_path + def initialize(configurations, executable) @executable = executable - @init_script = create_init_script(root_path, configurations) + @init_script = create_init_script(configurations) end - def run(command, source_path) - args = [format_command(command, source_path)] + def run(command) + args = [command] # The configuration cache is an incubating feature that can be activated manually. # The gradle plugin for licenses does not support it so we prevent it to run for gradle version supporting it. - args << "--no-configuration-cache" if gradle_version >= "6.6" + args << "--no-configuration-cache" if gradle_version >= Gem::Version.new("6.6") Licensed::Shell.execute(@executable, "-q", "--init-script", @init_script.path, *args) end private - def gradle_version - @gradle_version ||= Licensed::Shell.execute(@executable, "--version").scan(/Gradle [\d+]\.[\d+]/).last.split(" ").last - end - - def create_init_script(path, configurations) - Dir.chdir(path) do - f = Tempfile.new(["init", ".gradle"], @root_path) - f.write( - <<~EOF - import com.github.jk1.license.render.CsvReportRenderer - import com.github.jk1.license.filter.LicenseBundleNormalizer - final configs = #{configurations.inspect} - - initscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "com.github.jk1:gradle-license-report:#{gradle_version >= "7.0" ? "2.0" : "1.17"}" + def create_init_script(configurations) + # we need to create extensions in the event that the user hasn't configured custom configurations + # to avoid hitting errors where core Gradle configurations are set with canBeResolved=false + configuration_map = configurations.map { |c| [c, "licensed#{c}"] }.to_h + configuration_dsl = configuration_map.map { |orig, custom| "#{custom}.extendsFrom(#{orig})" } + + f = Tempfile.new(["init", ".gradle"]) + f.write( + <<~EOF + import com.github.jk1.license.render.CsvReportRenderer + import com.github.jk1.license.filter.LicenseBundleNormalizer + final configs = #{configuration_map.values.inspect} + + initscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" } } + dependencies { + classpath "com.github.jk1:gradle-license-report:#{gradle_version >= Gem::Version.new("7.0") ? "2.0" : "1.17"}" + } + } - allprojects { - apply plugin: com.github.jk1.license.LicenseReportPlugin - licenseReport { - outputDir = "$rootDir/.gradle-licenses" - configurations = configs - renderers = [new CsvReportRenderer()] - filters = [new LicenseBundleNormalizer()] - } + allprojects { + configurations { + #{configuration_dsl.join("\n") } + } + + apply plugin: com.github.jk1.license.LicenseReportPlugin + licenseReport { + outputDir = "$rootDir/#{GRADLE_LICENSES_PATH}" + configurations = configs + renderers = [new CsvReportRenderer()] + filters = [new LicenseBundleNormalizer()] + } - task printDependencies { - doLast { - def dependencies = [] - configs.each { - configurations[it].resolvedConfiguration.resolvedArtifacts.each { artifact -> - def id = artifact.moduleVersion.id - dependencies << "{ \\"group\\": \\"${id.group}\\", \\"name\\": \\"${id.name}\\", \\"version\\": \\"${id.version}\\" }" - } - } - println "[${dependencies.join(", ")}]" - } + task printDependencies { + doLast { + def dependencies = [] + configs.each { + configurations[it].resolvedConfiguration.resolvedArtifacts.each { artifact -> + def id = artifact.moduleVersion.id + dependencies << "{ \\"group\\": \\"${id.group}\\", \\"name\\": \\"${id.name}\\", \\"version\\": \\"${id.version}\\" }" + } + } + println "[${dependencies.join(", ")}]" } } - EOF - ) - f.close - f - end + } + EOF + ) + f.close + f end - # Prefixes the gradle command with the project name for multi-build projects. - def format_command(command, source_path) - Dir.chdir(source_path) do - path = Licensed::Shell.execute(@executable, "properties", "-Dorg.gradle.logging.level=quiet").scan(/path:.*/).last.split(" ").last - path == ":" ? command : "#{path}:#{command}" + # Returns the version of gradle used during execution + def gradle_version + @gradle_version ||= begin + version = Licensed::Shell.execute(@executable, "--version").scan(/Gradle [\d+]\.[\d+]/).last.split(" ").last + Gem::Version.new(version) end end end diff --git a/test/fixtures/gradle/multi_project/build.gradle b/test/fixtures/gradle/multi_project/build.gradle index 0eae7bfc..482923d1 100644 --- a/test/fixtures/gradle/multi_project/build.gradle +++ b/test/fixtures/gradle/multi_project/build.gradle @@ -10,12 +10,12 @@ buildscript { } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10" } } plugins { - id "org.jetbrains.kotlin.jvm" version "1.3.21" + id "org.jetbrains.kotlin.jvm" version "1.8.10" } group = 'com.github' @@ -29,4 +29,4 @@ repositories { dependencies { implementation project(path: ":app") testImplementation("org.junit.jupiter:junit-jupiter:5.4.0") -} \ No newline at end of file +} diff --git a/test/fixtures/gradle/single_project/build.gradle b/test/fixtures/gradle/single_project/build.gradle index 57218636..df4b9f0c 100644 --- a/test/fixtures/gradle/single_project/build.gradle +++ b/test/fixtures/gradle/single_project/build.gradle @@ -10,12 +10,12 @@ buildscript { } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10" } } plugins { - id "org.jetbrains.kotlin.jvm" version "1.3.21" + id "org.jetbrains.kotlin.jvm" version "1.8.10" } group = 'com.github' diff --git a/test/sources/gradle_test.rb b/test/sources/gradle_test.rb index 07c2230a..9272631b 100644 --- a/test/sources/gradle_test.rb +++ b/test/sources/gradle_test.rb @@ -5,10 +5,13 @@ if Licensed::Shell.tool_available?("gradle") describe Licensed::Sources::Gradle do + let(:opts) { { "source_path" => fixtures, "root" => root } } + let(:config) { Licensed::AppConfiguration.new(opts) } + let(:source) { Licensed::Sources::Gradle.new(config) } + describe "Single project" do - let(:fixtures) { File.expand_path("../../fixtures/gradle/single_project", __FILE__) } - let(:config) { Licensed::AppConfiguration.new({ "source_path" => Dir.pwd, "root" => fixtures }) } - let(:source) { Licensed::Sources::Gradle.new(config) } + let(:root) { File.expand_path("../../fixtures/gradle/single_project", __FILE__) } + let(:fixtures) { root } describe "enabled?" do it "is true if build.gradle exists and gradle is available" do @@ -53,20 +56,10 @@ end describe "Multi project" do - let(:fixtures) { File.expand_path("../../fixtures/gradle/multi_project", __FILE__) } - let(:config) { Licensed::Configuration.new({ - "apps" => [{ "source_path" => "#{Dir.pwd}/lib" }, { "source_path" => "#{Dir.pwd}/app" }], - "gradle" => { "configurations" => "runtimeClasspath" }, - "root" => fixtures - }) - } - let(:appConfig) { config.apps.last } - let(:libConfig) { config.apps.last } - let(:source) { Licensed::Sources::Gradle.new(appConfig) } + let(:root) { File.expand_path("../../fixtures/gradle/multi_project", __FILE__) } describe "app subproject" do - let(:appConfig) { config.apps.last } - let(:source) { Licensed::Sources::Gradle.new(appConfig) } + let(:fixtures) { File.join(root, "app") } describe "enabled?" do it "is true if build.gradle exists and gradle is available" do @@ -111,8 +104,8 @@ end describe "lib subproject" do - let(:appConfig) { config.apps.first } - let(:source) { Licensed::Sources::Gradle.new(appConfig) } + let(:fixtures) { File.join(root, "lib") } + describe "enabled?" do it "is true if build.gradle exists and gradle is available" do Dir.chdir(fixtures) do @@ -159,7 +152,7 @@ describe Licensed::Sources::Gradle::Dependency do let(:fixtures) { File.expand_path("../../fixtures/gradle/single_project", __FILE__) } - let(:config) { Licensed::AppConfiguration.new({ "source_path" => Dir.pwd, "root" => fixtures }) } + let(:config) { Licensed::AppConfiguration.new({ "source_path" => fixtures, "root" => fixtures }) } let(:source) { Licensed::Sources::Gradle.new(config) } it "returns the dependency license" do