-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sort class members to ensure deterministic builds
Class methods and fields are currently sorted at serialization (see DescriptorSerializer.sort) and at deserialization (see DeserializedMemberScope.OptimizedImplementation#addMembers). Therefore, the contents of the generated stub files are sorted in incremental builds but not in clean builds. The consequence is that the contents of the generated stub files may not be consistent across a clean build and an incremental build, making the build non-deterministic and dependent tasks run unnecessarily (see KT-40882). To work around that, this commit sorts class methods and fields when outputting stub files. Bug: KT-40882 (there are actually 2 issues in here; this commit fixes the first one) Test: New DeterministicBuildIT + Updated existing test expectation files
- Loading branch information
1 parent
07a797c
commit 4bf63a9
Showing
70 changed files
with
1,119 additions
and
1,016 deletions.
There are no files selected for viewing
93 changes: 93 additions & 0 deletions
93
...gin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/DeterministicBuildIT.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. | ||
*/ | ||
|
||
package org.jetbrains.kotlin.gradle | ||
|
||
import org.jetbrains.kotlin.gradle.util.allJavaFiles | ||
import org.junit.Test | ||
import java.io.File | ||
import kotlin.test.assertEquals | ||
|
||
/** Tests that the outputs of a build are deterministic. */ | ||
class DeterministicBuildIT : BaseGradleIT() { | ||
|
||
@Test | ||
fun `test KaptGenerateStubsTask - KT-40882`() = with( | ||
Project("simple", directoryPrefix = "kapt2") | ||
) { | ||
setupWorkingDir() | ||
projectDir | ||
.resolve("src/main/java/Foo.kt") | ||
.writeText( | ||
""" | ||
class Foo : Bar { | ||
// The fields and methods are ordered such that any sorting by KGP will be detected. | ||
val fooField1 = 1 | ||
val fooField3 = 3 | ||
val fooField2 = 2 | ||
fun fooMethod1() {} | ||
fun fooMethod3() {} | ||
fun fooMethod2() {} | ||
} | ||
""".trimIndent() | ||
) | ||
projectDir | ||
.resolve("src/main/java/Bar.kt") | ||
.writeText( | ||
""" | ||
interface Bar { | ||
val barField1 = 1 | ||
val barField3 = 3 | ||
val barField2 = 2 | ||
fun barMethod1() {} | ||
fun barMethod3() {} | ||
fun barMethod2() {} | ||
} | ||
""".trimIndent() | ||
) | ||
|
||
val buildAndSnapshotStubFiles: () -> Map<File, String> = { | ||
lateinit var stubFiles: Map<File, String> | ||
build(":kaptGenerateStubsKotlin") { | ||
assertSuccessful() | ||
assertTasksExecuted(":kaptGenerateStubsKotlin") | ||
stubFiles = fileInWorkingDir("build/tmp/kapt3/stubs").allJavaFiles().map { | ||
it to it.readText() | ||
}.toMap() | ||
} | ||
stubFiles | ||
} | ||
|
||
// Run the first build | ||
val stubFilesAfterFirstBuild = buildAndSnapshotStubFiles() | ||
|
||
// Make a change | ||
projectDir.resolve("src/main/java/Foo.kt").also { | ||
it.writeText( | ||
""" | ||
class Foo : Bar { | ||
val fooField1 = 1 | ||
val fooField3 = 3 | ||
val fooField2 = 2 | ||
fun fooMethod1() { println("Method body changed!") } | ||
fun fooMethod3() {} | ||
fun fooMethod2() {} | ||
} | ||
""".trimIndent() | ||
) | ||
} | ||
|
||
// Run the second build | ||
val stubFilesAfterSecondBuild = buildAndSnapshotStubFiles() | ||
|
||
// Check that the build outputs are deterministic | ||
assertEquals(stubFilesAfterFirstBuild.size, stubFilesAfterSecondBuild.size) | ||
for (file in stubFilesAfterFirstBuild.keys) { | ||
val fileContentsAfterFirstBuild = stubFilesAfterFirstBuild[file] | ||
val fileContentsAfterSecondBuild = stubFilesAfterSecondBuild[file] | ||
assertEquals(fileContentsAfterFirstBuild, fileContentsAfterSecondBuild) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.