diff --git a/oss-licenses-plugin/gradle.properties b/oss-licenses-plugin/gradle.properties index 5660b3a..e8692dd 100644 --- a/oss-licenses-plugin/gradle.properties +++ b/oss-licenses-plugin/gradle.properties @@ -8,3 +8,4 @@ systemProp.com.google.protobuf.use_unsafe_pre22_gencode=true org.gradle.configuration-cache=true org.gradle.caching=true +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m diff --git a/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.jar b/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.jar index 1b33c55..d997cfc 100644 Binary files a/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.jar and b/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.properties b/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.properties index 37f78a6..dbc3ce4 100644 --- a/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/oss-licenses-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/oss-licenses-plugin/gradlew b/oss-licenses-plugin/gradlew index 23d15a9..0262dcb 100755 --- a/oss-licenses-plugin/gradlew +++ b/oss-licenses-plugin/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/oss-licenses-plugin/gradlew.bat b/oss-licenses-plugin/gradlew.bat index 5eed7ee..e509b2d 100644 --- a/oss-licenses-plugin/gradlew.bat +++ b/oss-licenses-plugin/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/ArtifactFiles.groovy b/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/ArtifactFiles.groovy index bfba719..3208aa9 100644 --- a/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/ArtifactFiles.groovy +++ b/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/ArtifactFiles.groovy @@ -16,13 +16,24 @@ package com.google.android.gms.oss.licenses.plugin +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import java.io.Serializable /** * Data class to hold the resolved physical files for a single dependency. */ class ArtifactFiles implements Serializable { + @InputFile + @PathSensitive(PathSensitivity.NONE) + @Optional File pomFile + + @InputFile + @PathSensitive(PathSensitivity.NONE) + @Optional File libraryFile ArtifactFiles(File pomFile, File libraryFile) { diff --git a/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/DependencyTask.groovy b/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/DependencyTask.groovy index e62df28..493a2a8 100644 --- a/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/DependencyTask.groovy +++ b/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/DependencyTask.groovy @@ -21,8 +21,12 @@ import groovy.json.JsonBuilder import groovy.json.JsonGenerator import org.gradle.api.DefaultTask import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction import org.slf4j.LoggerFactory @@ -37,6 +41,7 @@ import static com.android.tools.build.libraries.metadata.Library.LibraryOneofCas * If the protobuf is not present (e.g. debug variants) it writes a single * dependency on the {@link DependencyUtil#ABSENT_ARTIFACT}. */ +@CacheableTask abstract class DependencyTask extends DefaultTask { private static final logger = LoggerFactory.getLogger(DependencyTask.class) @@ -44,7 +49,8 @@ abstract class DependencyTask extends DefaultTask { abstract RegularFileProperty getDependenciesJson() @InputFile - @org.gradle.api.tasks.Optional + @PathSensitive(PathSensitivity.NONE) + @Optional abstract RegularFileProperty getLibraryDependenciesReport() @TaskAction diff --git a/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/LicensesTask.groovy b/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/LicensesTask.groovy index e79f0da..6b24316 100644 --- a/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/LicensesTask.groovy +++ b/oss-licenses-plugin/src/main/groovy/com/google/android/gms/oss/licenses/plugin/LicensesTask.groovy @@ -21,10 +21,14 @@ import groovy.xml.XmlSlurper import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction import org.slf4j.LoggerFactory @@ -38,6 +42,7 @@ import java.util.zip.ZipFile * mappings (POMs and Library artifacts) are provided as lazy input properties, * making the task a pure function of its inputs. */ +@CacheableTask abstract class LicensesTask extends DefaultTask { private static final String UTF_8 = "UTF-8" private static final byte[] LINE_SEPARATOR = System @@ -66,10 +71,11 @@ abstract class LicensesTask extends DefaultTask { * A map of GAV coordinates (group:name:version) to their resolved POM and Library files. * Populated by OssLicensesPlugin during configuration. */ - @org.gradle.api.tasks.Input + @Nested abstract org.gradle.api.provider.MapProperty getArtifactFiles() @InputFile + @PathSensitive(PathSensitivity.NONE) abstract RegularFileProperty getDependenciesJson() @OutputDirectory diff --git a/oss-licenses-plugin/src/test/java/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt b/oss-licenses-plugin/src/test/java/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt index 9bbfda9..2bb6712 100644 --- a/oss-licenses-plugin/src/test/java/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt +++ b/oss-licenses-plugin/src/test/java/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt @@ -35,8 +35,12 @@ abstract class EndToEndTest(private val agpVersion: String, private val gradleVe private lateinit var projectDir: File private fun createRunner(vararg arguments: String): GradleRunner { + return createRunnerWithDir(projectDir, *arguments) + } + + private fun createRunnerWithDir(dir: File, vararg arguments: String): GradleRunner { return GradleRunner.create() - .withProjectDir(projectDir) + .withProjectDir(dir) .withGradleVersion(gradleVersion) .forwardOutput() // Isolate TestKit per AGP version subclass to allow parallel execution @@ -49,7 +53,11 @@ abstract class EndToEndTest(private val agpVersion: String, private val gradleVe @Before fun setup() { projectDir = tempDirectory.newFolder("basic") - File(projectDir, "build.gradle").writeText( + setupProject(projectDir) + } + + private fun setupProject(dir: File) { + File(dir, "build.gradle").writeText( """ plugins { id("com.android.application") version "$agpVersion" @@ -68,13 +76,13 @@ abstract class EndToEndTest(private val agpVersion: String, private val gradleVe } """.trimIndent() ) - File(projectDir, "gradle.properties").writeText( + File(dir, "gradle.properties").writeText( """ android.useAndroidX=true com.google.protobuf.use_unsafe_pre22_gencode=true """.trimIndent() ) - File(projectDir, "settings.gradle").writeText( + File(dir, "settings.gradle").writeText( """ pluginManagement { repositories { @@ -192,16 +200,72 @@ abstract class EndToEndTest(private val agpVersion: String, private val gradleVe // Gson 2.8.9 specifically uses the Apache 2.0 license URL. Assert.assertTrue(content.contains("apache.org/licenses/LICENSE-2.0")) } + + @Test + fun testRelocatability() { + val cacheDir = tempDirectory.newFolder("cache") + val dir1 = tempDirectory.newFolder("dir1") + val dir2 = tempDirectory.newFolder("dir2") + + // Helper to populate a directory with the test project + fun populate(dir: File) { + // ONLY copy the source files, NEVER the build outputs or local cache state + projectDir.listFiles()?.forEach { file -> + if (file.name != "build" && file.name != ".gradle") { + file.copyRecursively(File(dir, file.name), overwrite = true) + } + } + + // Update the settings.gradle to point to the correct repo path in the new location + File(dir, "settings.gradle").writeText( + """ + pluginManagement { + repositories { + maven { + url = uri("${System.getProperty("repo_path")}") + } + google() + mavenCentral() + } + } + + buildCache { + local { + directory = '${cacheDir.absolutePath.replace("\\", "/")}' + } + } + """.trimIndent() + ) + } + populate(dir1) + populate(dir2) + + // 1. Run in dir1 to prime the cache + val result1 = createRunnerWithDir(dir1, "releaseOssLicensesTask", "--build-cache").build() + Assert.assertEquals(TaskOutcome.SUCCESS, result1.task(":releaseOssLicensesTask")?.outcome) + + // 2. Run in dir2 (different absolute path) and expect FROM-CACHE + val result2 = createRunnerWithDir(dir2, "releaseOssLicensesTask", "--build-cache").build() + + Assert.assertEquals( + "LicensesTask should be relocatable", + TaskOutcome.FROM_CACHE, + result2.task(":releaseOssLicensesTask")?.outcome + ) + Assert.assertEquals( + "DependencyTask should be relocatable", + TaskOutcome.FROM_CACHE, + result2.task(":releaseOssDependencyTask")?.outcome + ) + } } -class EndToEndTest_AGP74_G75 : EndToEndTest("7.4.2", "7.5") -class EndToEndTest_AGP80_G80 : EndToEndTest("8.0.0", "8.0") -class EndToEndTest_AGP82_G82 : EndToEndTest("8.2.0", "8.2") -class EndToEndTest_AGP87_G89 : EndToEndTest("8.7.0", "8.9") -class EndToEndTest_AGP810_G811 : EndToEndTest("8.10.0", "8.11.1") -class EndToEndTest_AGP812_G814 : EndToEndTest("8.12.2", "8.14") -class EndToEndTest_AGP90_G90 : EndToEndTest("9.0.0-alpha03", "9.0.0") -class EndToEndTest_AGP91_G931 : EndToEndTest("9.1.0-alpha05", "9.3.1") +class EndToEndTest_AGP74_G75 : EndToEndTest("7.4.2", "7.5.1") +class EndToEndTest_AGP80_G80 : EndToEndTest("8.0.2", "8.0.2") +class EndToEndTest_AGP87_G89 : EndToEndTest("8.7.3", "8.9") +class EndToEndTest_AGP812_G814 : EndToEndTest("8.12.2", "8.14.1") +class EndToEndTest_AGP_STABLE_90_G90 : EndToEndTest("9.0.1", "9.1.0") +class EndToEndTest_AGP_ALPHA_92_G94 : EndToEndTest("9.2.0-alpha02", "9.4.0") private fun expectedDependenciesJson(builtInKotlinEnabled: Boolean, agpVersion: String) = """[ { @@ -382,7 +446,7 @@ private fun expectedDependenciesJson(builtInKotlinEnabled: Boolean, agpVersion: { "group": "org.jetbrains.kotlin", "name": "kotlin-stdlib", - "version": "${if (agpVersion.startsWith("9.1")) "2.2.10" else "2.2.0"}"""" else ""} + "version": "${if (agpVersion.startsWith("9"))"2.2.10" else "2.2.0"}"""" else ""} } ]"""