Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Isolated Projects support #6351

Merged
merged 2 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,11 @@ POM_DEVELOPER_NAME=Apollo

android.useAndroidX=true

# Keep in sync with other projects
# Give more memory to the Gradle daemon
org.gradle.jvmargs=-Xmx8g
# Do not automatically add stdlib dependency
kotlin.stdlib.default.dependency=false
# Enable the build cache
org.gradle.caching=true
# Enable the configuration cache
org.gradle.configuration-cache=true

#org.gradle.unsafe.isolated-projects=true
org.gradle.parallel=true

org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,15 @@ abstract class DefaultApolloExtension(
null -> { // default: automatic detection
project.configurations.configureEach {
it.dependencies.configureEach {
// Try to detect if a native version of apollo-normalized-cache-sqlite is in the classpath
if (it.group?.contains("apollo") == true
/*
* Try to detect if a native version of apollo-normalized-cache-sqlite is in the classpath
* This is a heuristic and will not work in 100% of the cases.
*
* Note: we only check external dependencies as reading the group of project dependencies
* is not compatible with isolated projects
*/
if (it is ExternalModuleDependency
&& it.group?.contains("apollo") == true
&& it.name.contains("normalized-cache-sqlite")
&& !it.name.contains("jvm")
&& !it.name.contains("android")) {
Expand Down Expand Up @@ -360,10 +367,8 @@ abstract class DefaultApolloExtension(

it.inputs.property("allVersions", Callable {
val allDeps = (
getDeps(project.rootProject.buildscript.configurations) +
getDeps(project.buildscript.configurations) +
getDeps(project.configurations)

)
allDeps.distinct().sorted()
})
Expand Down Expand Up @@ -1033,12 +1038,16 @@ abstract class DefaultApolloExtension(
.filter {
/**
* When using plugins {}, the group is the plugin id, not the maven group
*/
/**
*
* the "_" check is for refreshVersions,
* see https://github.com/jmfayard/refreshVersions/issues/507
*
* Note: we only check external dependencies as reading the group of project dependencies
* is not compatible with isolated projects
*
*/
it.group in listOf("com.apollographql.apollo", "com.apollographql.apollo.external")
it is ExternalModuleDependency
&& it.group in listOf("com.apollographql.apollo", "com.apollographql.apollo.external")
&& it.version != "_"
}.mapNotNull { dependency ->
dependency.version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ fun Project.apolloGetKotlinPluginVersion(): String? {
return project.getKotlinPluginVersion()
}

/*
* Inspired by SQLDelight:
* https://github.com/sqldelight/sqldelight/blob/ae8c348f6cf76822828bc65832106ec151ca5b6c/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/kotlin/LinkSqlite.kt#L7
* https://github.com/sqldelight/sqldelight/issues/1442
*
* Ideally this can be forwarded automatically, but I don't think this can be done as of today.
*/
internal fun linkSqlite(project: Project) {
val extension = project.kotlinMultiplatformExtension ?: return

Expand Down
7 changes: 5 additions & 2 deletions libraries/apollo-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ tasks.register("cleanStaleTestProjects") {
}
}

tasks.withType<Test> {
tasks.register("publishDependencies") {
dependsOn("publishAllPublicationsToPluginTestRepository")
dependsOn(":apollo-annotations:publishAllPublicationsToPluginTestRepository")
dependsOn(":apollo-api:publishAllPublicationsToPluginTestRepository")
dependsOn(":apollo-ast:publishAllPublicationsToPluginTestRepository")
Expand All @@ -143,8 +144,10 @@ tasks.withType<Test> {
dependsOn(":apollo-compiler:publishAllPublicationsToPluginTestRepository")
dependsOn(":apollo-gradle-plugin-external:publishAllPublicationsToPluginTestRepository")
dependsOn(":apollo-tooling:publishAllPublicationsToPluginTestRepository")
dependsOn("publishAllPublicationsToPluginTestRepository")
}

tasks.withType<Test> {
dependsOn("publishDependencies")
dependsOn("cleanStaleTestProjects")

addRelativeInput("testFiles", "testFiles")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class GradleToolingTests {

@Test
fun `tooling model exposes apollo metadata dependencies`() {
TestUtils.withTestProject("multi-modules-diamond") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-diamond") { dir ->

val toolingModel = GradleConnector.newConnector()
.forProjectDirectory(File(dir, "leaf"))
.connect()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import util.TestUtils
import com.google.common.truth.Truth
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Test
import util.disableIsolatedProjects
import java.io.File

class KotlinPluginVersionTests {
Expand All @@ -14,6 +15,8 @@ class KotlinPluginVersionTests {
@Test
fun `kotlin JVM min version succeeds`() {
TestUtils.withTestProject("kotlin-plugin-version-min") { dir ->
dir.disableIsolatedProjects() // old KGP versions do not support isolated projects

val result = TestUtils.executeTask("build", dir)

Truth.assertThat(result.task(":build")!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import org.gradle.testkit.runner.UnexpectedBuildFailure
import org.junit.Assert
import org.junit.Test
import util.TestUtils
import util.disableIsolatedProjects
import java.io.File

class LanguageVersionTests {
@Test
fun `compiling with 1_5 features with Kotlin 1_5 is working`() {
withProject(kotlinLanguageVersion = "1.5", apolloLanguageVersion = "1.5") { dir ->
dir.disableIsolatedProjects() // old KGP versions do not support isolated projects
TestUtils.executeTaskAndAssertSuccess(":assemble", dir)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,21 @@ apollo {

val apolloConfiguration = """
abstract class InstallGraphQLFilesTask: DefaultTask() {
@get:InputDirectory
abstract val inputDir: DirectoryProperty

@get:OutputDirectory
abstract val outputDir: DirectoryProperty

@TaskAction
fun taskAction() {
println("installing graphql files")
project.file( "src/main/graphql/com/example").copyRecursively(outputDir.asFile.get())
inputDir.asFile.get().copyRecursively(outputDir.asFile.get())
}
}
val installTask = tasks.register("installTask", InstallGraphQLFilesTask::class.java) {
outputDir.set(project.file("build/toto"))
inputDir.set(project.file("src/main/graphql/com/example"))
}
apollo {
service("service") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@ import org.gradle.testkit.runner.UnexpectedBuildFailure
import org.junit.Assert
import org.junit.Test
import util.TestUtils
import util.disableIsolatedProjects
import util.replaceInText
import java.io.File


internal fun testProjectWithIsolatedProjectsWorkaround(name: String, block: (File) -> Unit) {
/*
* There seems to be an issue running KGP in project isolation mode
* It's happening mostly for multi-module tests, I'm guessing because of a race or so.
* See https://youtrack.jetbrains.com/issue/KT-74394
*/
TestUtils.withTestProject(name) { dir ->
dir.disableIsolatedProjects()
block(dir)
}
}

class MultiModulesTests {
@Test
fun `multi-modules project compiles`() {
TestUtils.withTestProject("multi-modules") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules") { dir ->
val result = TestUtils.executeTask(":leaf:assemble", dir)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":leaf:assemble")!!.outcome)
}
}

@Test
fun `multi-modules project can use transitive dependencies`() {
TestUtils.withTestProject("multi-modules-transitive") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-transitive") { dir ->
val result = TestUtils.executeTask(":leaf:assemble", dir)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":leaf:assemble")!!.outcome)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":leaf:generateServiceApolloSources")!!.outcome)
Expand All @@ -32,15 +46,15 @@ class MultiModulesTests {
/**
* A diamond shaped hierarchy does not include the schema multiple times
*/
TestUtils.withTestProject("multi-modules-diamond") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-diamond") { dir ->
val result = TestUtils.executeTask(":leaf:jar", dir)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":leaf:generateServiceApolloSources")!!.outcome)
}
}

@Test
fun `duplicate fragments are detected correctly`() {
TestUtils.withTestProject("multi-modules-duplicates") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-duplicates") { dir ->
// duplicate fragments in sibling modules are fine
TestUtils.executeTaskAndAssertSuccess(":node1:impl:generateApolloSources", dir)

Expand All @@ -63,7 +77,7 @@ class MultiModulesTests {

@Test
fun `changing a fragment in module does not recompile siblings`() {
TestUtils.withTestProject("multi-modules-duplicates") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-duplicates") { dir ->
// Change the fragment so that it doesn't name clash anymore
File(dir, "node1/impl/src/main/graphql/com/library/operations.graphql").replaceInText("CatFragment", "CatFragment1")
// Execute jar a first time
Expand All @@ -89,7 +103,7 @@ class MultiModulesTests {

@Test
fun `custom scalars are registered if added to customScalarMappings`() {
TestUtils.withTestProject("multi-modules-custom-scalar") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-custom-scalar") { dir ->
TestUtils.executeTaskAndAssertSuccess(":leaf:assemble", dir)
// Date and GeoPoint is generated in the root module
Assert.assertTrue(File(dir, "root/build/generated/source/apollo/service/com/library/type/Date.kt").exists())
Expand All @@ -101,7 +115,7 @@ class MultiModulesTests {

@Test
fun `scalar mapping can only be registered in the schema module`() {
TestUtils.withTestProject("multi-modules-custom-scalar-defined-in-leaf") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-custom-scalar-defined-in-leaf") { dir ->
try {
TestUtils.executeTaskAndAssertSuccess(":leaf:assemble", dir)
Assert.fail("the build did not detect scalar mapping registered in leaf module")
Expand All @@ -113,15 +127,15 @@ class MultiModulesTests {

@Test
fun `metadata is published`() {
TestUtils.withTestProject("multi-modules-publishing-producer") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-publishing-producer") { dir ->
val result = TestUtils.executeTask(
"publishAllPublicationsToPluginTestRepository",
dir
)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":schema:publishAllPublicationsToPluginTestRepository")?.outcome)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":fragments:publishAllPublicationsToPluginTestRepository")?.outcome)
}
TestUtils.withTestProject("multi-modules-publishing-consumer") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-publishing-consumer") { dir ->
TestUtils.executeTaskAndAssertSuccess(
":build",
dir
Expand All @@ -131,23 +145,23 @@ class MultiModulesTests {

@Test
fun `schema targetLanguage propagates`() {
TestUtils.withTestProject("multi-modules-badconfig") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-badconfig") { dir ->
dir.resolve("root/build.gradle.kts").replacePlaceHolder("generateKotlinModels.set(false)")
TestUtils.executeTaskAndAssertSuccess(":leaf:build", dir)
}
}

@Test
fun `schema codegenModels propagates`() {
TestUtils.withTestProject("multi-modules-badconfig") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-badconfig") { dir ->
dir.resolve("root/build.gradle.kts").replacePlaceHolder("codegenModels.set(\"responseBased\")")
TestUtils.executeTaskAndAssertSuccess(":leaf:build", dir)
}
}

@Test
fun `bad targetLanguage is detected`() {
TestUtils.withTestProject("multi-modules-badconfig") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-badconfig") { dir ->
dir.resolve("root/build.gradle.kts").replacePlaceHolder("generateKotlinModels.set(true)")
dir.resolve("leaf/build.gradle.kts").replacePlaceHolder("generateKotlinModels.set(false)")

Expand All @@ -162,7 +176,7 @@ class MultiModulesTests {

@Test
fun `bad codegenModels is detected`() {
TestUtils.withTestProject("multi-modules-badconfig") { dir ->
testProjectWithIsolatedProjectsWorkaround("multi-modules-badconfig") { dir ->
dir.resolve("root/build.gradle.kts").replacePlaceHolder("codegenModels.set(\"responseBased\")")
dir.resolve("leaf/build.gradle.kts").replacePlaceHolder("codegenModels.set(\"operationBased\")")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import util.disableIsolatedProjects
import java.io.File

class AndroidProjectTests {
Expand Down Expand Up @@ -93,6 +94,7 @@ class AndroidProjectTests {
@Test
fun `kotlin Android min version succeeds`() {
withTestProject("kotlin-android-plugin-version") { dir ->
dir.disableIsolatedProjects()
val result = TestUtils.executeTask("build", dir)

Truth.assertThat(result.task(":build")!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ object TestUtils {
File(dest, "gradle.properties").writeText("""
|org.gradle.jvmargs=-Xmx4g
|
|org.gradle.unsafe.isolated-projects=true
""".trimMargin())

// dest is kept around for debug purposes. All test directories are removed
Expand Down Expand Up @@ -178,7 +179,11 @@ object TestUtils {
.forwardStdOutput(output)
.forwardStdError(error)
.withProjectDir(projectDir)
.withDebug(true)
/*
* Disable withDebug because it breaks with CC
* See https://github.com/gradle/gradle/issues/22765#issuecomment-1339427241
*/
//.withDebug(true)
.withArguments("--stacktrace", *args)
.apply {
if (gradleVersion != null) {
Expand Down Expand Up @@ -216,3 +221,9 @@ fun File.replaceInText(oldValue: Regex, newValue: String) {
val text = readText()
writeText(text.replace(oldValue, newValue))
}

fun File.disableIsolatedProjects() {
resolve("gradle.properties").let {
it.writeText(it.readText().replace("org.gradle.unsafe.isolated-projects=true", ""))
}
}
Loading