Triple-T / gradle-play-publisher

GPP is Android's unofficial release automation Gradle Plugin. It can do anything from building, uploading, and then promoting your App Bundle or APK to publishing app listings and other metadata.
MIT License
4.13k stars 341 forks source link

Support Gradle instant execution #854

Open SUPERCILEX opened 4 years ago

SUPERCILEX commented 3 years ago

Remove this use of project: https://github.com/Triple-T/gradle-play-publisher/blob/2b14f4556313975687f87e9a60c00e039368fdd2/play/plugin/src/main/kotlin/com/github/triplet/gradle/play/tasks/CommitEdit.kt#L19

SUPERCILEX commented 3 years ago

Waiting on a response to https://github.com/gradle/gradle/issues/16775#issuecomment-962545827. Otherwise we can create some hack tasks for the orElses.

SUPERCILEX commented 3 years ago

Tried and failed. The issue is that we need Gradle to switch configurations when dependencies change without tracking those dependencies. I think the solution might have to be splitting tasks into a version that always builds from source and one that uses artifactDir. Maybe it could be called publishPrebuiltBundle.

Index: play/plugin/src/main/kotlin/com/github/triplet/gradle/play/PlayPublisherPlugin.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/play/plugin/src/main/kotlin/com/github/triplet/gradle/play/PlayPublisherPlugin.kt b/play/plugin/src/main/kotlin/com/github/triplet/gradle/play/PlayPublisherPlugin.kt
--- a/play/plugin/src/main/kotlin/com/github/triplet/gradle/play/PlayPublisherPlugin.kt (revision dabf845a76b96b7e4c0b81dff6ddbd85f5d49373)
+++ b/play/plugin/src/main/kotlin/com/github/triplet/gradle/play/PlayPublisherPlugin.kt (date 1637719411302)
@@ -4,6 +4,7 @@
 import com.android.build.api.variant.ApplicationAndroidComponentsExtension
 import com.android.build.gradle.AppPlugin
 import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
+import com.android.tools.r8.internal.it
 import com.github.triplet.gradle.androidpublisher.ResolutionStrategy
 import com.github.triplet.gradle.common.utils.safeMkdirs
 import com.github.triplet.gradle.common.validation.validateRuntime
@@ -44,12 +45,18 @@
 import com.github.triplet.gradle.play.tasks.internal.PublishableTrackLifecycleTask
 import com.github.triplet.gradle.play.tasks.internal.UpdatableTrackLifecycleTask
 import com.github.triplet.gradle.play.tasks.internal.WriteTrackLifecycleTask
+import org.gradle.api.DefaultTask
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.Task
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.RegularFileProperty
 import org.gradle.api.plugins.ExtensionAware
 import org.gradle.api.provider.Provider
 import org.gradle.api.services.BuildServiceRegistration
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.TaskAction
 import org.gradle.kotlin.dsl.container
 import org.gradle.kotlin.dsl.create
 import org.gradle.kotlin.dsl.findPlugin
@@ -60,6 +67,7 @@
 import org.gradle.kotlin.dsl.registerIfAbsent
 import org.gradle.kotlin.dsl.the
 import org.gradle.kotlin.dsl.withType
+import org.gradle.work.DisableCachingByDefault

 @Suppress("unused") // Used by Gradle
 internal class PlayPublisherPlugin : Plugin<Project> {
@@ -196,6 +204,13 @@
                 return@v
             }

+            @Suppress("UNCHECKED_CAST") // Needed for overload ambiguity
+            fun getArtifactDependenciesHack(
+                    artifact: SingleArtifact<*>,
+            ): Provider<*> = extension.artifactDir.map<String> {
+                ""
+            }.orElse(variant.artifacts.get(artifact) as Provider<String>)
+
             fun findApkFiles(): Provider<List<String>> = extension.artifactDir.map {
                 val customDir = it.asFile
                 if (customDir.isFile && customDir.extension == "apk") {
@@ -210,25 +225,50 @@
                         ?.elements?.map { it.outputFile }.sneakyNull()
             })

-            fun findBundleFiles(): Provider<List<String>> = extension.artifactDir.map {
-                val customDir = it.asFile
-                if (customDir.isFile && customDir.extension == "aab") {
-                    listOf(it.asFile.absolutePath)
-                } else {
-                    it.asFileTree.matching {
-                        include("*.aab")
-                    }.map { it.absolutePath }
-                }
-            }.orElse(variant.artifacts.get(SingleArtifact.BUNDLE).map {
-                listOf(it.asFile.absolutePath)
-            })
+            @DisableCachingByDefault
+            abstract class BundleFilesConfigCacheHack : DefaultTask() {
+                @get:Internal
+                abstract val artifactDir: DirectoryProperty
+
+                @get:Internal
+                abstract val bundleArtifact: RegularFileProperty
+
+                @get:OutputFile
+                abstract val files: RegularFileProperty
+
+                init {
+                    outputs.upToDateWhen { false }
+                }
+
+                @TaskAction
+                fun writePaths() {
+                    val bundleFiles = artifactDir.map {
+                        val customDir = it.asFile
+                        if (customDir.isFile && customDir.extension == "aab") {
+                            listOf(it.asFile.absolutePath)
+                        } else {
+                            it.asFileTree.matching {
+                                include("*.aab")
+                            }.map { it.absolutePath }
+                        }
+                    }.orElse(bundleArtifact.map {
+                        listOf(it.asFile.absolutePath)
+                    })

-            @Suppress("UNCHECKED_CAST") // Needed for overload ambiguity
-            fun getArtifactDependenciesHack(
-                    artifact: SingleArtifact<*>,
-            ): Provider<*> = extension.artifactDir.map<String> {
-                ""
-            }.orElse(variant.artifacts.get(artifact) as Provider<String>)
+                    files.get().asFile.writeText(bundleFiles.get().joinToString("\n"))
+                }
+            }
+
+            val bundleFilesHackTask = project.newTask<BundleFilesConfigCacheHack>(
+                    "bundleFilesConfigCacheHack${taskVariantName}",
+            ) {
+                dependsOn(getArtifactDependenciesHack(SingleArtifact.BUNDLE))
+                files.set(project.layout.buildDirectory.file(
+                        "$INTERMEDIATES_OUTPUT_PATH/${variant.name}/bundle-files-hack.txt"))
+
+                artifactDir.set(extension.artifactDir)
+                bundleArtifact.set(variant.artifacts.get(SingleArtifact.BUNDLE))
+            }

             val appId = variant.applicationId.get()
             val api = project.gradle.sharedServices.registerIfAbsent(
@@ -277,11 +317,10 @@
                     arrayOf(extension, executionDir),
             ) {
                 apiService.set(api)
-                bundles.from(findBundleFiles())
+                bundles.from(bundleFilesHackTask.forUseAtConfigurationTime().map { it.files.get().asFile.readLines() })
                 outputDirectory.set(project.layout.buildDirectory.dir(
                         "outputs/internal-sharing/bundle/${variant.name}"))

-                dependsOn(getArtifactDependenciesHack(SingleArtifact.BUNDLE))
                 configure3pDeps(extension, taskVariantName)
             }
             publishInternalSharingBundleAllTask { dependsOn(publishInternalSharingBundleTask) }
@@ -459,9 +498,8 @@
                     arrayOf(extension, executionDir),
             ) {
                 configureInputs()
-                bundles.from(findBundleFiles())
+                bundles.from(bundleFilesHackTask.forUseAtConfigurationTime().map { it.files.get().asFile.readLines() })

-                dependsOn(getArtifactDependenciesHack(SingleArtifact.BUNDLE))
                 finalizedBy(commitEditTask)
                 configure3pDeps(extension, taskVariantName)
             }