From 3574f2671a341b9a8ced4d205f22dbd1a8cc0e1c Mon Sep 17 00:00:00 2001 From: Yang Date: Wed, 20 Apr 2022 19:50:15 +1000 Subject: [PATCH] Fix an issue where changing git HEAD does not invalidate task cache. --- api/app-versioning.api | 2 + .../tasks/GenerateAppVersionInfoTest.kt | 77 +++++++++++++++++++ .../appversioning/AppVersioningPlugin.kt | 19 +++++ .../appversioning/internal/GitClient.kt | 9 +++ .../tasks/GenerateAppVersionInfo.kt | 12 ++- 5 files changed, 118 insertions(+), 1 deletion(-) diff --git a/api/app-versioning.api b/api/app-versioning.api index dac027d7..5f2241f1 100644 --- a/api/app-versioning.api +++ b/api/app-versioning.api @@ -105,6 +105,7 @@ public final class io/github/reactivecircus/appversioning/internal/CommitId { public final class io/github/reactivecircus/appversioning/internal/GitClient { public static final field Companion Lio/github/reactivecircus/appversioning/internal/GitClient$Companion; public synthetic fun (Ljava/io/File;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun checkoutTag (Ljava/lang/String;)V public final fun commit-HhBVPuw (Ljava/lang/String;Z)Ljava/lang/String; public static synthetic fun commit-HhBVPuw$default (Lio/github/reactivecircus/appversioning/internal/GitClient;Ljava/lang/String;ZILjava/lang/Object;)Ljava/lang/String; public final fun describeLatestTag (Ljava/lang/String;)Ljava/lang/String; @@ -129,6 +130,7 @@ public abstract class io/github/reactivecircus/appversioning/tasks/GenerateAppVe public fun (Lorg/gradle/workers/WorkerExecutor;)V public final fun generate ()V public abstract fun getFetchTagsWhenNoneExistsLocally ()Lorg/gradle/api/provider/Property; + public abstract fun getGitHead ()Lorg/gradle/api/file/RegularFileProperty; public abstract fun getGitRefsDirectory ()Lorg/gradle/api/file/DirectoryProperty; public abstract fun getGroovyVersionCodeCustomizer ()Lorg/gradle/api/provider/Property; public abstract fun getGroovyVersionNameCustomizer ()Lorg/gradle/api/provider/Property; diff --git a/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfoTest.kt b/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfoTest.kt index 7169e9fb..90ec275e 100644 --- a/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfoTest.kt +++ b/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfoTest.kt @@ -946,6 +946,83 @@ class GenerateAppVersionInfoTest { gitClient.tag(name = "1.3.0", message = "2nd tag", commitId = commitId2) runner.runAndCheckResult( + "clean", + "generateAppVersionInfoForRelease", + "--build-cache" + ) { + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + } + } + + @Test + fun `GenerateAppVersionInfo (up-to-date) is re-executed after changing git HEAD`() { + val gitClient = GitClient.initialize(fixtureDir.root).apply { + val commitId1 = commit(message = "1st commit.") + tag(name = "1.2.3", message = "1st tag", commitId = commitId1) + val commitId2 = commit(message = "2nd commit.") + tag(name = "1.2.4", message = "2st tag", commitId = commitId2) + } + + val runner = withFixtureRunner( + fixtureDir = fixtureDir, + subprojects = listOf(AppProjectTemplate()) + ) + + runner.runAndCheckResult( + "generateAppVersionInfoForRelease" + ) { + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + } + + runner.runAndCheckResult( + "generateAppVersionInfoForRelease" + ) { + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.UP_TO_DATE) + } + + gitClient.checkoutTag(tag = "1.2.3") + + runner.runAndCheckResult( + "generateAppVersionInfoForRelease" + ) { + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + } + } + + @Test + fun `GenerateAppVersionInfo (from cache) is re-executed after changing git HEAD`() { + val gitClient = GitClient.initialize(fixtureDir.root).apply { + val commitId1 = commit(message = "1st commit.") + tag(name = "1.2.3", message = "1st tag", commitId = commitId1) + val commitId2 = commit(message = "2nd commit.") + tag(name = "1.2.4", message = "2st tag", commitId = commitId2) + } + + val runner = withFixtureRunner( + fixtureDir = fixtureDir, + subprojects = listOf(AppProjectTemplate()) + ) + + runner.runAndCheckResult( + "generateAppVersionInfoForRelease", + "--build-cache" + ) { + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + } + + runner.runAndCheckResult( + "clean", + "generateAppVersionInfoForRelease", + "--build-cache" + ) { + assertThat(task(":app:clean")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.FROM_CACHE) + } + + gitClient.checkoutTag(tag = "1.2.3") + + runner.runAndCheckResult( + "clean", "generateAppVersionInfoForRelease", "--build-cache" ) { diff --git a/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt b/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt index 672aae43..c7de010e 100644 --- a/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt +++ b/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt @@ -77,6 +77,7 @@ class AppVersioningPlugin : Plugin { group = APP_VERSIONING_TASK_GROUP description = "${GenerateAppVersionInfo.TASK_DESCRIPTION_PREFIX} for the ${variant.name} variant." gitRefsDirectory.set(findGitRefsDirectory(extension)) + gitHead.set(findGitHeadFile(extension)) rootProjectDirectory.set(project.rootProject.rootDir) rootProjectDisplayName.set(project.rootProject.displayName) fetchTagsWhenNoneExistsLocally.set(extension.fetchTagsWhenNoneExistsLocally) @@ -133,6 +134,22 @@ class AppVersioningPlugin : Plugin { } } + private fun Project.findGitHeadFile(extension: AppVersioningExtension): File? { + return when { + extension.bareGitRepoDirectory.isPresent -> { + extension.bareGitRepoDirectory.let { bareGitRepoDirectory -> + bareGitRepoDirectory.asFile.orNull?.resolve(HEAD_FILE)?.takeIf { it.exists() } + } + } + extension.gitRootDirectory.isPresent -> { + extension.gitRootDirectory.let { gitRootDirectory -> + gitRootDirectory.asFile.orNull?.resolve(STANDARD_GIT_HEAD_FILE)?.takeIf { it.exists() } + } + } + else -> project.rootProject.file(STANDARD_GIT_HEAD_FILE).takeIf { it.exists() } + } + } + companion object { private const val MIN_GRADLE_VERSION = "6.8" private const val MIN_AGP_VERSION = "7.0.0-beta04" @@ -142,6 +159,8 @@ class AppVersioningPlugin : Plugin { private const val APP_VERSIONING_TASK_GROUP = "versioning" private const val APP_VERSIONING_TASK_OUTPUT_DIR = "outputs/app_versioning" private const val REFS_DIRECTORY = "refs" +private const val HEAD_FILE = "HEAD" private const val STANDARD_GIT_REFS_DIRECTORY = ".git/$REFS_DIRECTORY" +private const val STANDARD_GIT_HEAD_FILE = ".git/$HEAD_FILE" private const val VERSION_CODE_RESULT_FILE = "version_code.txt" private const val VERSION_NAME_RESULT_FILE = "version_name.txt" diff --git a/src/main/kotlin/io/github/reactivecircus/appversioning/internal/GitClient.kt b/src/main/kotlin/io/github/reactivecircus/appversioning/internal/GitClient.kt index d7f32f4f..bb873cfa 100644 --- a/src/main/kotlin/io/github/reactivecircus/appversioning/internal/GitClient.kt +++ b/src/main/kotlin/io/github/reactivecircus/appversioning/internal/GitClient.kt @@ -59,6 +59,15 @@ class GitClient private constructor(private val projectDir: File) { command.execute(projectDir) } + fun checkoutTag(tag: String) { + val commitCommand = buildList { + add("git") + add("checkout") + add(tag) + } + commitCommand.execute(projectDir) + } + companion object { fun initialize(projectDir: File): GitClient { diff --git a/src/main/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfo.kt b/src/main/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfo.kt index 7a5a9282..3936f226 100644 --- a/src/main/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfo.kt +++ b/src/main/kotlin/io/github/reactivecircus/appversioning/tasks/GenerateAppVersionInfo.kt @@ -21,6 +21,7 @@ import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.IgnoreEmptyDirectories import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile @@ -48,6 +49,12 @@ abstract class GenerateAppVersionInfo @Inject constructor( @get:NormalizeLineEndings abstract val gitRefsDirectory: DirectoryProperty + @get:Optional + @get:InputFile + @get:PathSensitive(PathSensitivity.RELATIVE) + @get:NormalizeLineEndings + abstract val gitHead: RegularFileProperty + @get:Internal abstract val rootProjectDirectory: DirectoryProperty @@ -90,6 +97,7 @@ abstract class GenerateAppVersionInfo @Inject constructor( fun generate() { workerExecutor.noIsolation().submit(GenerateAppVersionInfoWorkAction::class.java) { gitRefsDirectory.set(this@GenerateAppVersionInfo.gitRefsDirectory) + gitHead.set(this@GenerateAppVersionInfo.gitHead) rootProjectDirectory.set(this@GenerateAppVersionInfo.rootProjectDirectory) rootProjectDisplayName.set(this@GenerateAppVersionInfo.rootProjectDisplayName) fetchTagsWhenNoneExistsLocally.set(this@GenerateAppVersionInfo.fetchTagsWhenNoneExistsLocally) @@ -114,6 +122,7 @@ abstract class GenerateAppVersionInfo @Inject constructor( private interface GenerateAppVersionInfoWorkParameters : WorkParameters { val gitRefsDirectory: DirectoryProperty + val gitHead: RegularFileProperty val rootProjectDirectory: DirectoryProperty val rootProjectDisplayName: Property val fetchTagsWhenNoneExistsLocally: Property @@ -135,6 +144,7 @@ private abstract class GenerateAppVersionInfoWorkAction @Inject constructor( override fun execute() { val gitRefsDirectory = parameters.gitRefsDirectory + val gitHead = parameters.gitHead val rootProjectDirectory = parameters.rootProjectDirectory val rootProjectDisplayName = parameters.rootProjectDisplayName val fetchTagsWhenNoneExistsLocally = parameters.fetchTagsWhenNoneExistsLocally @@ -147,7 +157,7 @@ private abstract class GenerateAppVersionInfoWorkAction @Inject constructor( val versionNameFile = parameters.versionNameFile val variantInfo = parameters.variantInfo - check(gitRefsDirectory.isPresent) { + check(gitRefsDirectory.isPresent && gitHead.isPresent) { "Android App Versioning Gradle Plugin works with git tags but ${rootProjectDisplayName.get()} is not a git root directory, and a valid gitRootDirectory is not provided." }