From 3280d1cf6e23d9fe592248ea8e6044ac4aa5fd08 Mon Sep 17 00:00:00 2001 From: Raine Cabal Date: Thu, 1 Aug 2024 17:08:29 -0700 Subject: [PATCH 1/8] fix: Handle `includeBuild` projects in dependency extractors --- .../paths/core/git/AffectedPathsTest.kt | 5 +- gradle.properties | 1 + .../support/android/VariantExtractor.kt | 6 +- .../support/android/VariantExtractorsTest.kt | 6 +- .../core/extractors/DependencyExtractors.kt | 71 +++++++++++++++++-- .../support/core/DependencyExtractorsTests.kt | 35 ++++++++- .../support/jvm/KotlinExtractorSupport.kt | 11 ++- .../support/jvm/TestVariantExtractor.kt | 9 +-- .../tooling/support/jvm/VariantExtractor.kt | 8 +-- .../support/jvm/VariantExtractorsTest.kt | 6 +- .../builder/SquareProjectModelBuilderTest.kt | 8 +-- 11 files changed, 131 insertions(+), 35 deletions(-) diff --git a/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt b/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt index 0ffcfca..1648b0d 100644 --- a/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt +++ b/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt @@ -292,7 +292,10 @@ class AffectedPathsTest { val result = analyzer.analyze() assertContentEquals(listOf("build2/foobar", "app", "library"), result.projectMap.keys) - assertContentEquals(listOf("build2/foobar"), result.affectedResults.flatMap { it.affectedProjectPaths }.distinct()) + assertContentEquals( + listOf("app", "app:debug:debugUnitTest", "build2/foobar", "app:release:releaseUnitTest"), + result.affectedResults.flatMap { it.affectedProjectPaths }.distinct() + ) } @Test diff --git a/gradle.properties b/gradle.properties index 4237d4f..4a6d9fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,3 +30,4 @@ SONATYPE_STAGING_PROFILE=com.squareup SONATYPE_HOST=S01 RELEASE_SIGNING_ENABLED=true SONATYPE_AUTOMATIC_RELEASE=true +RELEASE_SIGNING_ENABLED=false \ No newline at end of file diff --git a/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/VariantExtractor.kt b/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/VariantExtractor.kt index 438269a..fa8851c 100644 --- a/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/VariantExtractor.kt +++ b/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/VariantExtractor.kt @@ -19,8 +19,7 @@ package com.squareup.tooling.support.android import com.android.build.gradle.api.BaseVariant import com.squareup.tooling.models.SquareDependency -import com.squareup.tooling.support.core.extractors.extractDependencies -import com.squareup.tooling.support.core.extractors.extractSquareDependency +import com.squareup.tooling.support.core.extractors.extractSquareDependencies import org.gradle.api.Project import java.io.File @@ -77,8 +76,7 @@ internal fun BaseVariant.extractSquareVariantConfigurationParams( addAll(compileConfiguration.extendsFrom.map { it.name }) }.toTypedArray() - val deps = project.configurations.extractDependencies(*configNames) - .map { it.extractSquareDependency(project) } + val deps = project.configurations.extractSquareDependencies(project, *configNames) return srcs to deps.toSet() } diff --git a/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/VariantExtractorsTest.kt b/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/VariantExtractorsTest.kt index 5cd55a0..28f1e2a 100644 --- a/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/VariantExtractorsTest.kt +++ b/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/VariantExtractorsTest.kt @@ -53,7 +53,11 @@ class VariantExtractorsTest { "All source paths must be relative to the project dir" ) assertEquals(24, srcs.size, "Sources were missing") - assertTrue("No dependencies should be listed") { deps.isEmpty() } + // Filter out the kotlin-stdlib-jdk8 dependency + val filteredDeps = deps.filterNot { + it.target.contains("kotlin-stdlib") + } + assertTrue("No dependencies should be listed") { filteredDeps.isEmpty() } } @Test diff --git a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt index c703ea2..3f6576c 100644 --- a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt +++ b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt @@ -20,21 +20,74 @@ package com.squareup.tooling.support.core.extractors import com.squareup.tooling.models.SquareDependency import com.squareup.tooling.support.core.models.SquareDependency import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.result.ResolvedDependencyResult +import org.gradle.api.internal.artifacts.DefaultProjectComponentIdentifier import org.gradle.api.internal.artifacts.dependencies.AbstractExternalModuleDependency import org.gradle.api.internal.artifacts.dependencies.AbstractModuleDependency -// Extracts Gradle Dependency objects from the given configurations -public fun ConfigurationContainer.extractDependencies( +public fun ConfigurationContainer.extractSquareDependencies( + project: Project, vararg configurationNames: String -): Sequence { - return configurationNames.asSequence().flatMap { configurationName -> - getByName(configurationName).allDependencies.asSequence() - } +): Sequence { + return configurationNames.asSequence() + .map { configurationName -> getByName(configurationName) } + .flatMap { configuration -> + sequence { + yieldAll(configuration.extractDependencies() + .map { it.extractSquareDependency(project) }) + yieldAll(configuration.extractResolvedProjectDependencies()) + } + } +} + +/** + * Extracts Gradle Dependency objects from the given configurations + */ +public fun Configuration.extractDependencies(): Sequence { + return allDependencies.asSequence() +} + +/** + * Extracts project dependencies from the resolved artifacts of the configuration. + * + * In cases where an included build is used (e.g., through `includeBuild`), project dependencies + * may not appear in the standard `Configuration.allDependencies` list. Instead, they are + * resolved during the configuration resolution process. + * + * It only works if the configuration can be resolved (`isCanBeResolved` is true), which excludes + * configurations like `compileOnly`. + */ +public fun Configuration.extractResolvedProjectDependencies(): Sequence { + if (!isCanBeResolved) return emptySequence() + + val resolutionResult = incoming.resolutionResult + val allDependencies = resolutionResult.allDependencies + val directDependencies = resolutionResult.root.dependencies.toSet() + + return allDependencies.asSequence() + .mapNotNull { it as? ResolvedDependencyResult } + .mapNotNull { resolvedDependencyResult -> + val identifier = resolvedDependencyResult.selected.id as? DefaultProjectComponentIdentifier + identifier?.let { + if (it.identityPath.path != ":") { + val path = gradlePathToFilePath(it.identityPath.path) + val isTransitive = resolvedDependencyResult !in directDependencies + SquareDependency( + target = path, + tags = if (isTransitive) setOf("transitive") else emptySet() + ) + } else { + null + } + } + } } + // Converts the given Gradle Dependency into a SquareDependency use to construct the model project public fun Dependency.extractSquareDependency(project: Project): SquareDependency { return when (this) { @@ -71,7 +124,7 @@ public fun Dependency.extractSquareDependency(project: Project): SquareDependenc // Meant to de-duplicate project name from target string. private fun Dependency.keyRelativeTo(relative: String = ""): String { if (this is ProjectDependency) { - return dependencyProject.path.replace(':', '/') + return gradlePathToFilePath(dependencyProject.path) } val s = group?.split(".", ":", "/") ?: emptyList() val result = when (s.firstOrNull()) { @@ -80,3 +133,7 @@ private fun Dependency.keyRelativeTo(relative: String = ""): String { } return result.plus(name).joinToString("") { "/$it" } } + +private fun gradlePathToFilePath(path: String): String { + return path.replace(':', '/') +} diff --git a/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt b/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt index 841f283..4918cad 100644 --- a/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt +++ b/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt @@ -18,7 +18,9 @@ package com.squareup.tooling.support.core import com.squareup.tooling.support.core.extractors.extractDependencies +import com.squareup.tooling.support.core.extractors.extractResolvedProjectDependencies import com.squareup.tooling.support.core.extractors.extractSquareDependency +import com.squareup.tooling.support.core.models.SquareDependency import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Test import kotlin.test.assertEquals @@ -34,7 +36,7 @@ class DependencyExtractorsTests { project.dependencies.add("testConfig", "com.squareup:foo") project.dependencies.add("testConfig", "com.squareup:bar") - val result = project.configurations.extractDependencies("testConfig").toList() + val result = project.configurations.getByName("testConfig").extractDependencies().toList() // Test assertEquals(2, result.size) @@ -106,4 +108,35 @@ class DependencyExtractorsTests { return@assertTrue result.target == "/squareTest" } } + + @Test + fun `test extractResolvedProjectDependencies() with empty project dependencies`() { + // Setup + val project = ProjectBuilder.builder().build() + project.configurations.create("testConfig") + + // Test + val configuration = project.configurations.getByName("testConfig") + + val result = configuration.extractResolvedProjectDependencies() + assertTrue(result.none(), "The result should be an empty sequence") + } + + @Test + fun `test extractResolvedProjectDependencies() with resolved project dependencies`() { + // Setup + val project = ProjectBuilder.builder().build() + project.configurations.create("testConfig") + val projectDependency = ProjectBuilder.builder().withName("squareTest").withParent(project).build() + projectDependency.configurations.create("default") + project.dependencies.add("testConfig", projectDependency) + + // Test + val configuration = project.configurations.getByName("testConfig") + + val result = configuration.extractResolvedProjectDependencies() + assertEquals(1, result.count()) + assertTrue(result.contains(SquareDependency(target = "/squareTest"))) + } + } diff --git a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/KotlinExtractorSupport.kt b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/KotlinExtractorSupport.kt index 566cda6..e33121e 100644 --- a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/KotlinExtractorSupport.kt +++ b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/KotlinExtractorSupport.kt @@ -19,8 +19,7 @@ package com.squareup.tooling.support.jvm import com.squareup.tooling.models.SquareDependency import com.squareup.tooling.models.SquareTestConfiguration -import com.squareup.tooling.support.core.extractors.extractDependencies -import com.squareup.tooling.support.core.extractors.extractSquareDependency +import com.squareup.tooling.support.core.extractors.extractSquareDependencies import com.squareup.tooling.support.core.models.SquareTestConfiguration import org.gradle.api.Project import org.gradle.api.tasks.SourceSet @@ -33,10 +32,11 @@ internal fun KotlinSourceSet.extractSquareTestConfiguration( ): SquareTestConfiguration { return SquareTestConfiguration( srcs = kotlin.sourceDirectories.map { it.toRelativeString(project.projectDir) }.toSet(), - deps = project.configurations.extractDependencies( + deps = project.configurations.extractSquareDependencies( + project, implementationMetadataConfigurationName, compileOnlyMetadataConfigurationName - ).map { it.extractSquareDependency(project) }.toSet() + ).toSet() ) } @@ -78,8 +78,7 @@ internal fun KotlinSourceSet.extractSquareVariantConfigurationParams( ) }.toTypedArray() - val result = project.configurations.extractDependencies(*configNames) - .map { it.extractSquareDependency(project) }.toList() + val result = project.configurations.extractSquareDependencies(project,*configNames).toList() deps.addAll(result) return srcs to deps diff --git a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/TestVariantExtractor.kt b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/TestVariantExtractor.kt index b53f78c..0cd7924 100644 --- a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/TestVariantExtractor.kt +++ b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/TestVariantExtractor.kt @@ -18,8 +18,7 @@ package com.squareup.tooling.support.jvm import com.squareup.tooling.models.SquareTestConfiguration -import com.squareup.tooling.support.core.extractors.extractDependencies -import com.squareup.tooling.support.core.extractors.extractSquareDependency +import com.squareup.tooling.support.core.extractors.extractSquareDependencies import com.squareup.tooling.support.core.models.SquareTestConfiguration import org.gradle.api.Project import org.gradle.api.tasks.SourceSet @@ -28,7 +27,9 @@ import org.gradle.api.tasks.SourceSet internal fun SourceSet.extractSquareTestConfiguration(project: Project): SquareTestConfiguration { return SquareTestConfiguration( srcs = allSource.sourceDirectories.map { it.toRelativeString(project.projectDir) }.toSet(), - deps = project.configurations.extractDependencies(compileClasspathConfigurationName) - .map { it.extractSquareDependency(project) }.toSet() + deps = project.configurations.extractSquareDependencies( + project, + compileClasspathConfigurationName + ).toSet() ) } diff --git a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt index ef61e0a..69a3565 100644 --- a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt +++ b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt @@ -18,8 +18,7 @@ package com.squareup.tooling.support.jvm import com.squareup.tooling.models.SquareDependency -import com.squareup.tooling.support.core.extractors.extractDependencies -import com.squareup.tooling.support.core.extractors.extractSquareDependency +import com.squareup.tooling.support.core.extractors.extractSquareDependencies import org.gradle.api.Project import org.gradle.api.tasks.SourceSet @@ -67,10 +66,7 @@ internal fun SourceSet.extractSquareVariantConfigurationParams( ) }.toTypedArray() - deps.addAll( - project.configurations.extractDependencies(*configNames) - .map { it.extractSquareDependency(project) } - ) + deps.addAll(project.configurations.extractSquareDependencies(project, *configNames)) return srcs to deps } diff --git a/tooling/support/jvm/src/test/kotlin/com/squareup/tooling/support/jvm/VariantExtractorsTest.kt b/tooling/support/jvm/src/test/kotlin/com/squareup/tooling/support/jvm/VariantExtractorsTest.kt index b88bd11..0574b89 100644 --- a/tooling/support/jvm/src/test/kotlin/com/squareup/tooling/support/jvm/VariantExtractorsTest.kt +++ b/tooling/support/jvm/src/test/kotlin/com/squareup/tooling/support/jvm/VariantExtractorsTest.kt @@ -106,7 +106,11 @@ class VariantExtractorsTest { val (srcs, deps) = kotlinSourceSet.extractSquareVariantConfigurationParams(appProject, "main") assertTrue(srcs.containsAll(listOf("src/main/java", "src/main/kotlin"))) - assertTrue("No dependencies should be listed") { deps.isEmpty() } + // Filter out the kotlin-stdlib-jdk8 dependency + val filteredDeps = deps.filterNot { + it.target.contains("kotlin-stdlib") + } + assertTrue("No dependencies should be listed") { filteredDeps.isEmpty() } } @Test diff --git a/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt b/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt index fc76962..754a3f5 100644 --- a/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt +++ b/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt @@ -107,7 +107,7 @@ class SquareProjectModelBuilderTest { ANDROID_SRC_DIRECTORY_PATHS.map { "src/main/$it" } ) } - assertTrue(debugVariant.deps.isEmpty()) + assertTrue(debugVariant.deps.filterNot { it.target.contains("kotlin-stdlib") }.isEmpty()) val releaseVariant = requireNotNull(result.variants["release"]) assertTrue { @@ -116,7 +116,7 @@ class SquareProjectModelBuilderTest { ANDROID_SRC_DIRECTORY_PATHS.map { "src/main/$it" } ) } - assertTrue(releaseVariant.deps.isEmpty()) + assertTrue(releaseVariant.deps.filterNot { it.target.contains("kotlin-stdlib") }.isEmpty()) // Check test variant properties val debugTestVariants = debugVariant.tests @@ -186,7 +186,7 @@ class SquareProjectModelBuilderTest { ANDROID_SRC_DIRECTORY_PATHS.map { "src/main/$it" } ) } - assertTrue(debugVariant.deps.isEmpty()) + assertTrue(debugVariant.deps.filterNot { it.target.contains("kotlin-stdlib") }.isEmpty()) val releaseVariant = requireNotNull(result.variants["release"]) assertTrue { @@ -195,7 +195,7 @@ class SquareProjectModelBuilderTest { ANDROID_SRC_DIRECTORY_PATHS.map { "src/main/$it" } ) } - assertTrue(releaseVariant.deps.isEmpty()) + assertTrue(releaseVariant.deps.filterNot { it.target.contains("kotlin-stdlib") }.isEmpty()) // Check test variant properties val debugTestVariants = debugVariant.tests From 2d6c40b69f51831505942ef406bc09771b41b824 Mon Sep 17 00:00:00 2001 From: Raine Cabal Date: Fri, 9 Aug 2024 11:06:55 -0700 Subject: [PATCH 2/8] Cleanup gradle.properties used for local testing --- gradle.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 4a6d9fe..3ef2b55 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,5 +29,4 @@ SONATYPE_STAGING_PROFILE=com.squareup SONATYPE_HOST=S01 RELEASE_SIGNING_ENABLED=true -SONATYPE_AUTOMATIC_RELEASE=true -RELEASE_SIGNING_ENABLED=false \ No newline at end of file +SONATYPE_AUTOMATIC_RELEASE=true \ No newline at end of file From 95311ddbbc417b3d661d77a6808618d89995bbe7 Mon Sep 17 00:00:00 2001 From: Raine Cabal Date: Fri, 9 Aug 2024 12:34:17 -0700 Subject: [PATCH 3/8] Conditionally include resolved project dependencies based on 'useIncludeBuild' flag --- .../kotlin/com/squareup/affected/paths/core/CoreOptions.kt | 1 + .../tooling/support/core/extractors/DependencyExtractors.kt | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt index f7b0c22..d3b2bf1 100644 --- a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt +++ b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt @@ -120,6 +120,7 @@ public data class CoreOptions @JvmOverloads constructor( internal val gradleArgs: List = buildList { addAll(customGradleFlags) + add("-PuseIncludeBuild=$useIncludeBuild") if (autoInjectPlugin) { add("-I") add( diff --git a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt index 3f6576c..302a85b 100644 --- a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt +++ b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt @@ -33,13 +33,16 @@ public fun ConfigurationContainer.extractSquareDependencies( project: Project, vararg configurationNames: String ): Sequence { + val useIncludeBuild = project.findProperty("useIncludeBuild") == "true" return configurationNames.asSequence() .map { configurationName -> getByName(configurationName) } .flatMap { configuration -> sequence { yieldAll(configuration.extractDependencies() .map { it.extractSquareDependency(project) }) - yieldAll(configuration.extractResolvedProjectDependencies()) + if (useIncludeBuild) { + yieldAll(configuration.extractResolvedProjectDependencies()) + } } } } From c936393de12c7fafc178a0bf2c3babb3d225579f Mon Sep 17 00:00:00 2001 From: Pablo Baxter Date: Sat, 10 Aug 2024 12:15:20 -0700 Subject: [PATCH 4/8] Add unit test to check for dependency substitution --- .../builder/SquareProjectModelBuilderTest.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt b/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt index 754a3f5..3e3b33d 100644 --- a/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt +++ b/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt @@ -341,6 +341,66 @@ class SquareProjectModelBuilderTest { assertTrue(debugTestVariants.keys.isEmpty()) } + @Test + fun `Ensure dependency substitution rules are accounted for during model building`() { + val projectModelBuilder = SquareProjectModelBuilder() + + val rootProject = ProjectBuilder + .builder() + .withProjectDir(temporaryFolder) + .withName("com.squareup.test") + .build() + + ProjectBuilder + .builder() + .withName("test-lib") + .withProjectDir(generateTestBuild(File(rootProject.projectDir, "test-lib"))) + .withParent(rootProject) + .build() + + // Add in the ":app" project + val app = ProjectBuilder + .builder() + .withName("app") + .withProjectDir(generateApplicationBuild(File(rootProject.projectDir, "app"))) + .withParent(rootProject) + .build() + + app.buildFile.appendText(""" + + dependencies { + implementation 'org.blah:blah' + } + """.trimIndent()) + + app.buildscript.configurations.all { config -> + config.resolutionStrategy.dependencySubstitution { substitution -> + substitution.substitute(substitution.module("org.blah:blah")) + .using(substitution.project(":test-lib")) + } + } + + app.forceEvaluate() + + val result = projectModelBuilder.buildAll(SquareProject::class.java.name, app) as SquareProject + + // Check SquareProject properties + assertEquals("app", result.name) + assertEquals("com.squareup.test", result.namespace) + assertEquals("app", result.pathToProject) + assertEquals("android-app", result.pluginUsed) + + assertTrue("Dependencies were not substituted") { + result.variants.values.all { configuration -> + configuration.deps.any { dep -> + dep.target == "/test-lib" + } && configuration.deps.none { dep -> + dep.target == "@maven://org.blah:blah" + } + } + } + } + @Test fun `Do not throw exception if a non-Java or non-Android plugin is used`() { val projectModelBuilder = SquareProjectModelBuilder() From 7a671bf47f2c02a5296921c7457da40522f78212 Mon Sep 17 00:00:00 2001 From: Pablo Baxter Date: Tue, 20 Aug 2024 17:35:13 -0700 Subject: [PATCH 5/8] Fix tests, remove includeBuild flag, cleanup dependency extractor --- .../affected/paths/core/CoreAnalyzer.kt | 5 +- .../affected/paths/core/CoreOptions.kt | 4 -- .../paths/core/utils/SquareToolingApi.kt | 31 +++-------- .../paths/core/git/AffectedPathsTest.kt | 3 +- gradle.properties | 2 +- .../core/extractors/DependencyExtractors.kt | 55 ++++++++++--------- 6 files changed, 40 insertions(+), 60 deletions(-) diff --git a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreAnalyzer.kt b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreAnalyzer.kt index 5ee71ab..336c099 100644 --- a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreAnalyzer.kt +++ b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreAnalyzer.kt @@ -101,10 +101,7 @@ public class CoreAnalyzer @JvmOverloads constructor(private val coreOptions: Cor ensureActive() val actionExecutor = projectConnection.action( - SquareBuildAction( - coreOptions.allowGradleParallel, - coreOptions.useIncludeBuild - ) + SquareBuildAction(coreOptions.allowGradleParallel) ) actionExecutor.withCancellationToken(cancellationTokenSource.token()) if (coreOptions.useBuildScan) { diff --git a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt index d3b2bf1..223eea2 100644 --- a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt +++ b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/CoreOptions.kt @@ -67,9 +67,6 @@ public data class CoreOptions @JvmOverloads constructor( /** Auto-injects the "com.squareup.tooling" plugin to all projects in the build */ val autoInjectPlugin: Boolean = true, - /** Include any "includeBuild" builds from the current build */ - val useIncludeBuild: Boolean = true, - /** Gradle distribution file to use */ val gradleDistributionPath: Path? = null, @@ -120,7 +117,6 @@ public data class CoreOptions @JvmOverloads constructor( internal val gradleArgs: List = buildList { addAll(customGradleFlags) - add("-PuseIncludeBuild=$useIncludeBuild") if (autoInjectPlugin) { add("-I") add( diff --git a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt index 609c651..04cf18c 100644 --- a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt +++ b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt @@ -35,8 +35,7 @@ private class ProjectBuildAction(private val project: Model) : BuildAction> { override fun execute(controller: BuildController): List { // Run the ProjectBuildAction in parallel, if we can @@ -44,27 +43,15 @@ internal class SquareBuildAction( val actions = buildList { // Include any builds along with the root build - if (useIncludeBuild) { - controller.buildModel.includedBuilds.forEach { build -> - addAll( - build.projects // All projects included in the "settings.gradle" file of all builds - .asSequence() - .map { project -> - return@map ProjectBuildAction(project) - } - ) - } + controller.buildModel.includedBuilds.forEach { build -> + addAll( + build.projects // All projects included in the "settings.gradle" file of all builds + .asSequence() + .map { project -> + return@map ProjectBuildAction(project) + } + ) } - - // The "BuildModel" is the Gradle build after evaluating the "settings.gradle" file - addAll( - controller.buildModel - .projects // All projects included in the "settings.gradle" file - .asSequence() - .map { project -> - return@map ProjectBuildAction(project) - }.toList() - ) } if (actions.isEmpty()) return emptyList() diff --git a/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt b/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt index 1648b0d..317ad30 100644 --- a/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt +++ b/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt @@ -206,8 +206,7 @@ class AffectedPathsTest { val analyzer = CoreAnalyzer( CoreOptions( directory = build1, - changedFiles = listOf("library/build.gradle"), - useIncludeBuild = false + changedFiles = listOf("library/build.gradle") ) ) diff --git a/gradle.properties b/gradle.properties index 3ef2b55..4237d4f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,4 +29,4 @@ SONATYPE_STAGING_PROFILE=com.squareup SONATYPE_HOST=S01 RELEASE_SIGNING_ENABLED=true -SONATYPE_AUTOMATIC_RELEASE=true \ No newline at end of file +SONATYPE_AUTOMATIC_RELEASE=true diff --git a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt index 302a85b..1fb1a37 100644 --- a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt +++ b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt @@ -24,26 +24,24 @@ import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.result.ResolvedDependencyResult -import org.gradle.api.internal.artifacts.DefaultProjectComponentIdentifier import org.gradle.api.internal.artifacts.dependencies.AbstractExternalModuleDependency import org.gradle.api.internal.artifacts.dependencies.AbstractModuleDependency +import org.jetbrains.kotlin.util.prefixIfNot +/** + * Extracts SquareDependency objects from the given configurations + */ public fun ConfigurationContainer.extractSquareDependencies( project: Project, vararg configurationNames: String ): Sequence { - val useIncludeBuild = project.findProperty("useIncludeBuild") == "true" return configurationNames.asSequence() .map { configurationName -> getByName(configurationName) } .flatMap { configuration -> - sequence { - yieldAll(configuration.extractDependencies() - .map { it.extractSquareDependency(project) }) - if (useIncludeBuild) { - yieldAll(configuration.extractResolvedProjectDependencies()) - } - } + configuration.extractResolvedProjectDependencies(project) } } @@ -55,36 +53,35 @@ public fun Configuration.extractDependencies(): Sequence { } /** - * Extracts project dependencies from the resolved artifacts of the configuration. - * - * In cases where an included build is used (e.g., through `includeBuild`), project dependencies - * may not appear in the standard `Configuration.allDependencies` list. Instead, they are - * resolved during the configuration resolution process. + * Extracts dependencies from the resolved artifacts of the configuration. * - * It only works if the configuration can be resolved (`isCanBeResolved` is true), which excludes - * configurations like `compileOnly`. + * If configuration is not resolvable, it will extract dependencies from the configuration itself. */ -public fun Configuration.extractResolvedProjectDependencies(): Sequence { - if (!isCanBeResolved) return emptySequence() +public fun Configuration.extractResolvedProjectDependencies(project: Project): Sequence { + if (!isCanBeResolved) return extractDependencies().map { it.extractSquareDependency(project) } val resolutionResult = incoming.resolutionResult val allDependencies = resolutionResult.allDependencies val directDependencies = resolutionResult.root.dependencies.toSet() - return allDependencies.asSequence() - .mapNotNull { it as? ResolvedDependencyResult } - .mapNotNull { resolvedDependencyResult -> - val identifier = resolvedDependencyResult.selected.id as? DefaultProjectComponentIdentifier - identifier?.let { - if (it.identityPath.path != ":") { - val path = gradlePathToFilePath(it.identityPath.path) + return allDependencies.asSequence().filterIsInstance() + .map { resolvedDependencyResult -> + val id = resolvedDependencyResult.selected.id + return@map when (id) { + is ProjectComponentIdentifier -> { + val path = gradlePathToFilePath(id.identityPath) val isTransitive = resolvedDependencyResult !in directDependencies SquareDependency( target = path, tags = if (isTransitive) setOf("transitive") else emptySet() ) - } else { - null + } + is ModuleComponentIdentifier -> { + SquareDependency(target = "@maven://${id.moduleIdentifier.group}:${id.moduleIdentifier.name}") + } + else -> { + println("WARNING: Unknown dep type $javaClass") + SquareDependency(target = id.displayName) } } } @@ -140,3 +137,7 @@ private fun Dependency.keyRelativeTo(relative: String = ""): String { private fun gradlePathToFilePath(path: String): String { return path.replace(':', '/') } + +private val ProjectComponentIdentifier.identityPath: String + get() = projectPath.prefixIfNot(build.buildPath) + From 97df7a594cb6c365dbb01aa98f6da1bc5962678a Mon Sep 17 00:00:00 2001 From: Pablo Baxter Date: Tue, 20 Aug 2024 17:35:33 -0700 Subject: [PATCH 6/8] Cleanup --- .../tooling/support/core/extractors/DependencyExtractors.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt index 1fb1a37..1b243a3 100644 --- a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt +++ b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt @@ -93,7 +93,7 @@ public fun Dependency.extractSquareDependency(project: Project): SquareDependenc return when (this) { // Used by maven dependencies. is AbstractExternalModuleDependency -> { - SquareDependency(target = "@maven://${group ?: "undefined"}:$name") + SquareDependency(target = "@maven://${group}:$name") } // Meant to capture non-project dependencies, but in reality captures project dependencies. From 023355f435264b5660dc742005318c00b8de8b38 Mon Sep 17 00:00:00 2001 From: Pablo Baxter Date: Wed, 21 Aug 2024 13:27:19 -0700 Subject: [PATCH 7/8] Ensure all dependencies are captured and fix unit tests --- .../paths/core/utils/SquareToolingApi.kt | 1 + .../paths/core/git/AffectedPathsTest.kt | 78 +-------------- .../tooling/support/android/TestExtractors.kt | 4 +- .../support/android/TestExtractorsTest.kt | 8 +- .../core/extractors/DependencyExtractors.kt | 98 +++++++++++++++---- .../support/core/DependencyExtractorsTests.kt | 16 ++- .../builder/SquareProjectModelBuilderTest.kt | 24 +++-- 7 files changed, 105 insertions(+), 124 deletions(-) diff --git a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt index 04cf18c..9657629 100644 --- a/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt +++ b/affected-paths/core/src/main/kotlin/com/squareup/affected/paths/core/utils/SquareToolingApi.kt @@ -42,6 +42,7 @@ internal class SquareBuildAction( val canRunParallel = controller.getCanQueryProjectModelInParallel(SquareProject::class.java) val actions = buildList { + addAll(controller.buildModel.projects.asSequence().map { project -> ProjectBuildAction(project) }) // Include any builds along with the root build controller.buildModel.includedBuilds.forEach { build -> addAll( diff --git a/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt b/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt index 317ad30..8d71845 100644 --- a/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt +++ b/affected-paths/core/src/test/kotlin/com/squareup/affected/paths/core/git/AffectedPathsTest.kt @@ -9,6 +9,7 @@ import kotlin.io.path.createDirectories import kotlin.io.path.writeText import kotlin.test.Test import kotlin.test.assertContentEquals +import kotlin.test.assertEquals import kotlin.time.Duration.Companion.minutes class AffectedPathsTest { @@ -139,80 +140,7 @@ class AffectedPathsTest { val result = analyzer.analyze() - assertContentEquals(listOf("build2/foobar", "app", "library"), result.projectMap.keys) - assertContentEquals(listOf("app", "app:debug:debugUnitTest", "library", "app:release:releaseUnitTest"), result.affectedResults.flatMap { it.affectedProjectPaths }.distinct()) - } - - @Test - fun `Ignores projects in included builds when useIncludeBuild is false`() = runTest(timeout = 3.minutes) { - // Prep - val build1 = root.resolve("build1").createDirectories() - val build2 = build1.resolve("build2").createDirectories() - createSettingsFile( - rootDir = build1, - contents = """ - rootProject.name = 'blah' - includeBuild 'build2' - include 'app' - include 'library' - """.trimIndent() - ) - - createModule( - rootDir = build1, - name = "app", - contents = - """ - plugins { - id 'application' - } - - dependencies { - implementation project(':library') - } - """.trimIndent() - ) - - createModule( - rootDir = build1, - name = "library", - contents = - """ - plugins { - id 'java' - } - """.trimIndent() - ) - - createSettingsFile( - rootDir = build2, - contents = """ - rootProject.name = 'blah2' - include 'foobar' - """.trimIndent() - ) - - createModule( - rootDir = build2, - name = "foobar", - contents = - """ - plugins { - id 'java' - } - """.trimIndent() - ) - - val analyzer = CoreAnalyzer( - CoreOptions( - directory = build1, - changedFiles = listOf("library/build.gradle") - ) - ) - - val result = analyzer.analyze() - - assertContentEquals(listOf("app", "library"), result.projectMap.keys) + assertEquals(setOf("build2/foobar", "app", "library"), result.projectMap.keys) assertContentEquals(listOf("app", "app:debug:debugUnitTest", "library", "app:release:releaseUnitTest"), result.affectedResults.flatMap { it.affectedProjectPaths }.distinct()) } @@ -290,7 +218,7 @@ class AffectedPathsTest { val result = analyzer.analyze() - assertContentEquals(listOf("build2/foobar", "app", "library"), result.projectMap.keys) + assertEquals(setOf("build2/foobar", "app", "library"), result.projectMap.keys) assertContentEquals( listOf("app", "app:debug:debugUnitTest", "build2/foobar", "app:release:releaseUnitTest"), result.affectedResults.flatMap { it.affectedProjectPaths }.distinct() diff --git a/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/TestExtractors.kt b/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/TestExtractors.kt index 6ab9cec..10503a6 100644 --- a/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/TestExtractors.kt +++ b/tooling/support/android/src/main/kotlin/com/squareup/tooling/support/android/TestExtractors.kt @@ -21,7 +21,7 @@ import com.android.build.gradle.api.BaseVariant import com.android.build.gradle.api.TestVariant import com.android.build.gradle.api.UnitTestVariant import com.squareup.tooling.models.SquareTestConfiguration -import com.squareup.tooling.support.core.extractors.extractSquareDependency +import com.squareup.tooling.support.core.extractors.extractResolvedProjectDependencies import com.squareup.tooling.support.core.models.SquareTestConfiguration import org.gradle.api.Project @@ -55,6 +55,6 @@ private fun BaseVariant.extractSquareTestConfiguration(project: Project): Square }.map { it.toRelativeString(project.projectDir) } return SquareTestConfiguration( srcs = dirs.toSet(), - deps = compileConfiguration.allDependencies.map { it.extractSquareDependency(project) }.toSet() + deps = compileConfiguration.extractResolvedProjectDependencies(project).toSet() ) } diff --git a/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/TestExtractorsTest.kt b/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/TestExtractorsTest.kt index 4d5432c..d5a72be 100644 --- a/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/TestExtractorsTest.kt +++ b/tooling/support/android/src/test/kotlin/com/squareup/tooling/support/android/TestExtractorsTest.kt @@ -54,8 +54,8 @@ class TestExtractorsTest { val squareUnitTestConfiguration = unitTestVariant .extractSquareTestConfiguration(appProject) - assertEquals(1, squareUnitTestConfiguration.deps.size) - assertTrue { squareUnitTestConfiguration.deps.all { it.target == "/app" } } + assertEquals(2, squareUnitTestConfiguration.deps.size) + assertTrue { squareUnitTestConfiguration.deps.any { it.target == "/app" } } // Test the TestVariant val testVariant = appProject.extensions.getByType(AppExtension::class.java).testVariants.first() @@ -66,7 +66,7 @@ class TestExtractorsTest { squareTestConfiguration.srcs.all { it.startsWith("src/") }, "All source paths must be relative to the project dir" ) - assertEquals(1, squareTestConfiguration.deps.size) - assertTrue { squareTestConfiguration.deps.all { it.target == "/app" } } + assertEquals(2, squareTestConfiguration.deps.size) + assertTrue { squareTestConfiguration.deps.any { it.target == "/app" } } } } diff --git a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt index 1b243a3..c1a39ff 100644 --- a/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt +++ b/tooling/support/core/src/main/kotlin/com/squareup/tooling/support/core/extractors/DependencyExtractors.kt @@ -25,11 +25,14 @@ import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.component.ModuleComponentSelector import org.gradle.api.artifacts.component.ProjectComponentIdentifier +import org.gradle.api.artifacts.component.ProjectComponentSelector import org.gradle.api.artifacts.result.ResolvedDependencyResult +import org.gradle.api.artifacts.result.UnresolvedDependencyResult import org.gradle.api.internal.artifacts.dependencies.AbstractExternalModuleDependency import org.gradle.api.internal.artifacts.dependencies.AbstractModuleDependency -import org.jetbrains.kotlin.util.prefixIfNot +import org.gradle.util.GradleVersion /** * Extracts SquareDependency objects from the given configurations @@ -64,24 +67,61 @@ public fun Configuration.extractResolvedProjectDependencies(project: Project): S val allDependencies = resolutionResult.allDependencies val directDependencies = resolutionResult.root.dependencies.toSet() - return allDependencies.asSequence().filterIsInstance() - .map { resolvedDependencyResult -> - val id = resolvedDependencyResult.selected.id - return@map when (id) { - is ProjectComponentIdentifier -> { - val path = gradlePathToFilePath(id.identityPath) - val isTransitive = resolvedDependencyResult !in directDependencies - SquareDependency( - target = path, - tags = if (isTransitive) setOf("transitive") else emptySet() - ) - } - is ModuleComponentIdentifier -> { - SquareDependency(target = "@maven://${id.moduleIdentifier.group}:${id.moduleIdentifier.name}") + return allDependencies.asSequence() + .map { dependencyResult -> + when (dependencyResult) { + is ResolvedDependencyResult -> { + return@map when (val id = dependencyResult.selected.id) { + is ProjectComponentIdentifier -> { + val path = gradlePathToFilePath(id.identityPath) + val isTransitive = dependencyResult !in directDependencies + SquareDependency( + target = path, + tags = if (isTransitive) setOf("transitive") else emptySet() + ) + } + + is ModuleComponentIdentifier -> { + @Suppress("UselessCallOnNotNull") + SquareDependency( + target = "@maven://${id.moduleIdentifier.group.orEmpty().ifBlank { "undefined" }}:${id.moduleIdentifier.name}" + ) + } + + else -> { + println("WARNING: Unknown dep type $javaClass") + SquareDependency(target = id.displayName) + } + } + } + + is UnresolvedDependencyResult -> { + return@map when (val id = dependencyResult.requested) { + is ProjectComponentSelector -> { + val path = gradlePathToFilePath(id.identityPath) + val isTransitive = dependencyResult !in directDependencies + SquareDependency( + target = path, + tags = if (isTransitive) setOf("transitive") else emptySet() + ) + } + + is ModuleComponentSelector -> { + @Suppress("UselessCallOnNotNull") + SquareDependency( + target = "@maven://${id.moduleIdentifier.group.orEmpty().ifBlank { "undefined" }}:${id.moduleIdentifier.name}" + ) + } + + else -> { + println("WARNING: Unknown dep type $javaClass") + SquareDependency(target = id.displayName) + } + } } + else -> { - println("WARNING: Unknown dep type $javaClass") - SquareDependency(target = id.displayName) + return@map SquareDependency("unknown") } } } @@ -89,11 +129,12 @@ public fun Configuration.extractResolvedProjectDependencies(project: Project): S // Converts the given Gradle Dependency into a SquareDependency use to construct the model project -public fun Dependency.extractSquareDependency(project: Project): SquareDependency { +private fun Dependency.extractSquareDependency(project: Project): SquareDependency { return when (this) { // Used by maven dependencies. is AbstractExternalModuleDependency -> { - SquareDependency(target = "@maven://${group}:$name") + @Suppress("UselessCallOnNotNull") + SquareDependency(target = "@maven://${group.orEmpty().ifBlank { "undefined" }}:$name") } // Meant to capture non-project dependencies, but in reality captures project dependencies. @@ -135,9 +176,24 @@ private fun Dependency.keyRelativeTo(relative: String = ""): String { } private fun gradlePathToFilePath(path: String): String { - return path.replace(':', '/') + val filePath = path.replace(':', '/') + return if (filePath.startsWith('/')) filePath else "/$filePath" } private val ProjectComponentIdentifier.identityPath: String - get() = projectPath.prefixIfNot(build.buildPath) + get() { + return if (GradleVersion.current() >= GradleVersion.version("8.2")) { + if (projectPath.startsWith(build.buildPath)) projectPath else "${build.buildPath}$projectPath" + } else { + if (projectPath.startsWith(build.name)) projectPath else "${build.name}$projectPath" + } + } +private val ProjectComponentSelector.identityPath: String + get() { + return if (GradleVersion.current() >= GradleVersion.version("8.2")) { + if (projectPath.startsWith(buildPath)) projectPath else "$buildPath$projectPath" + } else { + if (projectPath.startsWith(buildName)) projectPath else "$buildName$projectPath" + } + } diff --git a/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt b/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt index 4918cad..f31cade 100644 --- a/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt +++ b/tooling/support/core/src/test/kotlin/com/squareup/tooling/support/core/DependencyExtractorsTests.kt @@ -19,7 +19,6 @@ package com.squareup.tooling.support.core import com.squareup.tooling.support.core.extractors.extractDependencies import com.squareup.tooling.support.core.extractors.extractResolvedProjectDependencies -import com.squareup.tooling.support.core.extractors.extractSquareDependency import com.squareup.tooling.support.core.models.SquareDependency import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Test @@ -53,7 +52,7 @@ class DependencyExtractorsTests { // Test val configuration = project.configurations.getByName("testConfig") - val result = configuration.dependencies.map { it.extractSquareDependency(project) }.first() + val result = configuration.extractResolvedProjectDependencies(project).first() assertTrue("AbstractExternalModuleDependency should not set tags") { return@assertTrue result.tags.isEmpty() @@ -74,12 +73,11 @@ class DependencyExtractorsTests { // Test val configuration = project.configurations.getByName("testConfig") - val result = configuration.dependencies.map { it.extractSquareDependency(project) }.first() + val result = configuration.extractResolvedProjectDependencies(project).first() assertTrue("AbstractExternalModuleDependency should not set tags") { return@assertTrue result.tags.isEmpty() } - println(result) assertTrue("AbstractExternalModuleDependency target incorrect") { return@assertTrue result.target == "@maven://undefined:foo" } @@ -96,12 +94,12 @@ class DependencyExtractorsTests { // Test val configuration = project.configurations.getByName("testConfig") - val result = configuration.dependencies.map { it.extractSquareDependency(project) }.first() + val result = configuration.extractResolvedProjectDependencies(project).first() assertEquals( - expected = 1, + expected = 0, actual = result.tags.size, - message = "Transitive tag not applied" + message = "Transitive tag applied" ) println(result) assertTrue("AbstractModuleDependency target incorrect") { @@ -118,7 +116,7 @@ class DependencyExtractorsTests { // Test val configuration = project.configurations.getByName("testConfig") - val result = configuration.extractResolvedProjectDependencies() + val result = configuration.extractResolvedProjectDependencies(project) assertTrue(result.none(), "The result should be an empty sequence") } @@ -134,7 +132,7 @@ class DependencyExtractorsTests { // Test val configuration = project.configurations.getByName("testConfig") - val result = configuration.extractResolvedProjectDependencies() + val result = configuration.extractResolvedProjectDependencies(project) assertEquals(1, result.count()) assertTrue(result.contains(SquareDependency(target = "/squareTest"))) } diff --git a/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt b/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt index 3e3b33d..049ae6c 100644 --- a/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt +++ b/tooling/support/src/test/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilderTest.kt @@ -86,7 +86,7 @@ class SquareProjectModelBuilderTest { .withParent(rootProject) .build() - val expectedTestDependency = SquareDependency("/app", setOf("transitive")) + val expectedTestDependency = SquareDependency("/app") appProject.forceEvaluate() @@ -165,7 +165,7 @@ class SquareProjectModelBuilderTest { .withParent(rootProject) .build() - val expectedTestDependency = SquareDependency("/lib", setOf("transitive")) + val expectedTestDependency = SquareDependency("/lib") libProject.forceEvaluate() @@ -368,18 +368,18 @@ class SquareProjectModelBuilderTest { app.buildFile.appendText(""" + configurations.all { config -> + config.resolutionStrategy.dependencySubstitution { substitution -> + substitution.substitute(substitution.module("org.blah:blah")) + .using(substitution.project(":test-lib")) + } + } + dependencies { - implementation 'org.blah:blah' + implementation 'org.blah:blah:' } """.trimIndent()) - app.buildscript.configurations.all { config -> - config.resolutionStrategy.dependencySubstitution { substitution -> - substitution.substitute(substitution.module("org.blah:blah")) - .using(substitution.project(":test-lib")) - } - } - app.forceEvaluate() val result = projectModelBuilder.buildAll(SquareProject::class.java.name, app) as SquareProject @@ -391,11 +391,9 @@ class SquareProjectModelBuilderTest { assertEquals("android-app", result.pluginUsed) assertTrue("Dependencies were not substituted") { - result.variants.values.all { configuration -> + result.variants.values.any { configuration -> configuration.deps.any { dep -> dep.target == "/test-lib" - } && configuration.deps.none { dep -> - dep.target == "@maven://org.blah:blah" } } } From a3cdcdcc6e4747acb88c66d1c2938be6f5d6f789 Mon Sep 17 00:00:00 2001 From: Pablo Baxter Date: Wed, 21 Aug 2024 13:27:51 -0700 Subject: [PATCH 8/8] General cleanup --- gradle/libs.versions.toml | 2 +- tooling/models/build.gradle | 4 ---- .../com/squareup/tooling/support/jvm/VariantExtractor.kt | 1 + .../tooling/support/builder/SquareProjectModelBuilder.kt | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b46285e..6d83a49 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ logback = "1.4.5" koin = "3.3.0" -jgit = "6.4.0.202211300538-r" +jgit = "6.10.0.202406032230-r" vanniktech = "0.25.3" diff --git a/tooling/models/build.gradle b/tooling/models/build.gradle index 63eea31..bc84605 100644 --- a/tooling/models/build.gradle +++ b/tooling/models/build.gradle @@ -2,7 +2,3 @@ plugins { id 'square-lib' id 'square-publishing' } - -dependencies { - compileOnly(gradleApi()) -} diff --git a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt index 69a3565..030703a 100644 --- a/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt +++ b/tooling/support/jvm/src/main/kotlin/com/squareup/tooling/support/jvm/VariantExtractor.kt @@ -54,6 +54,7 @@ internal fun SourceSet.extractSquareVariantConfigurationParams( } } + @Suppress("UselessCallOnNotNull", "RemoveExplicitTypeArguments") val configNames = buildList { add(compileClasspathConfigurationName) addAll( diff --git a/tooling/support/src/main/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilder.kt b/tooling/support/src/main/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilder.kt index a0d00e5..6def00a 100644 --- a/tooling/support/src/main/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilder.kt +++ b/tooling/support/src/main/kotlin/com/squareup/tooling/support/builder/SquareProjectModelBuilder.kt @@ -42,6 +42,7 @@ private class SquareProjectModelBuilderImpl : SquareProjectModelBuilder { return modelName == SquareProject::class.java.name } + // The `Any?` return type is valid. Ignore the error. override fun buildAll(modelName: String, project: Project): Any? { if (modelName == SquareProject::class.java.name) { return extractors.firstNotNullOfOrNull { it.extractSquareProject(project) }