From 30d3342a8e6c023a42069bf40d278cee7338eebf Mon Sep 17 00:00:00 2001 From: rinekri Date: Mon, 15 Apr 2024 18:18:50 +0200 Subject: [PATCH] Add logic to get and apply bundle path to PlayPublishTask --- plugin-build/plugin/build.gradle.kts | 4 +- .../publish/plugin/BuildPublishPlugin.kt | 87 +++++------- .../plugin/task/play/PlayDistributionTask.kt | 133 +++++++++--------- .../play/publisher/DefaultPlayPublisher.kt | 33 ----- .../play/publisher/InternalPlayPublisher.kt | 17 --- .../task/play/publisher/PublisherModels.kt | 8 +- .../plugin/task/play/publisher/Responses.kt | 88 ++++++------ .../task/play/track/DefaultEditManager.kt | 101 ------------- .../plugin/task/play/track/EditManager.kt | 43 +----- .../plugin/task/play/track/TrackManager.kt | 37 +---- .../plugin/task/play/work/PlayUploadWork.kt | 14 +- 11 files changed, 170 insertions(+), 395 deletions(-) diff --git a/plugin-build/plugin/build.gradle.kts b/plugin-build/plugin/build.gradle.kts index 91b9db2..734ff52 100644 --- a/plugin-build/plugin/build.gradle.kts +++ b/plugin-build/plugin/build.gradle.kts @@ -33,7 +33,7 @@ gradlePlugin { id = "ru.kode.android.build-publish" displayName = "Configure project with Firebase App Distribution and changelogs" implementationClass = "ru.kode.android.build.publish.plugin.BuildPublishPlugin" - version = "1.3.2" + version = project.version description = "Android plugin to publish bundles and apks to Firebase App Distribution with changelogs" tags.set(listOf("firebase", "publish", "changelog", "build")) } @@ -45,7 +45,7 @@ publishing { create("maven") { groupId = project.group.toString() artifactId = "ru.kode.android.build-publish".removePrefix("$groupId.") - version = "1.3.2" + version = project.version.toString() from(components["java"]) } diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/BuildPublishPlugin.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/BuildPublishPlugin.kt index 0f5b730..75f0803 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/BuildPublishPlugin.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/BuildPublishPlugin.kt @@ -2,11 +2,11 @@ package ru.kode.android.build.publish.plugin +import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.ApplicationAndroidComponentsExtension import com.android.build.api.variant.impl.VariantOutputImpl import com.android.build.gradle.AppExtension import com.android.build.gradle.AppPlugin -import com.android.build.gradle.internal.tasks.PackageBundleTask import com.android.build.gradle.tasks.PackageAndroidArtifact import com.android.builder.model.Version.ANDROID_GRADLE_PLUGIN_VERSION import com.google.firebase.appdistribution.gradle.AppDistributionExtension @@ -19,7 +19,6 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty -import org.gradle.api.logging.Logging import org.gradle.api.provider.Provider import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.StopExecutionException @@ -51,7 +50,6 @@ import ru.kode.android.build.publish.plugin.util.capitalizedName import java.io.File import java.time.LocalDate import java.time.format.DateTimeFormatter -import java.util.logging.Logger internal const val SEND_SLACK_CHANGELOG_TASK_PREFIX = "sendSlackChangelog" internal const val SEND_TELEGRAM_CHANGELOG_TASK_PREFIX = "sendTelegramChangelog" @@ -93,27 +91,26 @@ abstract class BuildPublishPlugin : Plugin { androidExtension.onVariants( callback = { variant -> - Logging.getLogger(this::class.java).info("FOUND VARIANT: $variant WITH OUTPUT NAME ${variant.outputs - .find { it is VariantOutputImpl && it.fullName == variant.name } - as? VariantOutputImpl}") - val output = variant.outputs .find { it is VariantOutputImpl && it.fullName == variant.name } as? VariantOutputImpl if (output != null) { val buildVariant = BuildVariant(variant.name, variant.flavorName, variant.buildType) - val outputFileName = output.outputFileName.get() + val apkOutputFileName = output.outputFileName.get() + + val bundleFile = variant.artifacts.get(SingleArtifact.BUNDLE) val outputProviders = project.registerVariantTasks( buildPublishExtension, buildVariant, changelogFile, - outputFileName, + apkOutputFileName, + bundleFile, grgitService, ) output.versionCode.set(outputProviders.versionCode) - output.outputFileName.set(outputProviders.outputFileName) + output.outputFileName.set(outputProviders.apkOutputFileName) output.versionName.set(outputProviders.versionName) } }, @@ -138,7 +135,8 @@ abstract class BuildPublishPlugin : Plugin { buildPublishExtension: BuildPublishExtension, buildVariant: BuildVariant, changelogFile: Provider, - outputFileName: String, + apkOutputFileName: String, + bundleFile: Provider, grgitService: Provider, ): OutputProviders { val outputConfig = @@ -160,15 +158,15 @@ abstract class BuildPublishPlugin : Plugin { project.provider { DEFAULT_VERSION_CODE } } } - val outputFileNameProvider = + val apkOutputFileNameProvider = useVersionsFromTagProvider.flatMap { useVersionsFromTag -> if (useVersionsFromTag) { outputConfig.baseFileName.zip(tagBuildProvider) { baseFileName, tagBuildFile -> - mapToOutputFileName(tagBuildFile, outputFileName, baseFileName) + mapToOutputApkFileName(tagBuildFile, apkOutputFileName, baseFileName) } } else { outputConfig.baseFileName.map { baseFileName -> - createDefaultOutputFileName(baseFileName, outputFileName) + createDefaultOutputFileName(baseFileName, apkOutputFileName) } } } @@ -182,9 +180,9 @@ abstract class BuildPublishPlugin : Plugin { project.provider { DEFAULT_VERSION_NAME } } } - val outputFileProvider = - outputFileNameProvider.flatMap { fileName -> - mapToOutputFile(buildVariant, fileName) + val apkOutputFileProvider = + apkOutputFileNameProvider.flatMap { fileName -> + mapToOutputApkFile(buildVariant, fileName) } tasks.registerPrintLastIncreasedTagTask( buildVariant, @@ -230,7 +228,7 @@ abstract class BuildPublishPlugin : Plugin { buildVariant, generateChangelogFileProvider, tagBuildProvider, - outputFileProvider, + apkOutputFileProvider, ) } val appCenterDistributionConfig = @@ -243,7 +241,7 @@ abstract class BuildPublishPlugin : Plugin { config = appCenterDistributionConfig, buildVariant = buildVariant, changelogFileProvider = generateChangelogFileProvider, - buildVariantOutputFileProvider = outputFileProvider, + apkOutputFileProvider = apkOutputFileProvider, tagBuildProvider = tagBuildProvider, outputConfig = outputConfig, ) @@ -258,7 +256,7 @@ abstract class BuildPublishPlugin : Plugin { PlayTaskParams( config = playConfig, buildVariant = buildVariant, - buildVariantOutputFileProvider = outputFileProvider, + bundleOutputFileProvider = bundleFile, tagBuildProvider = tagBuildProvider, outputConfig = outputConfig, ) @@ -281,7 +279,7 @@ abstract class BuildPublishPlugin : Plugin { return OutputProviders( versionName = versionNameProvider, versionCode = versionCodeProvider, - outputFileName = outputFileNameProvider, + apkOutputFileName = apkOutputFileNameProvider, ) } @@ -323,7 +321,7 @@ abstract class BuildPublishPlugin : Plugin { buildVariant: BuildVariant, generateChangelogFileProvider: Provider, tagBuildProvider: Provider, - outputFileProvider: Provider, + apkOutputFileProvider: Provider, ) { registerSendSlackChangelogTask( outputConfig, @@ -341,7 +339,7 @@ abstract class BuildPublishPlugin : Plugin { slackConfig.uploadApiTokenFile, slackConfig.uploadChannels, buildVariant, - outputFileProvider, + apkOutputFileProvider, ) } } @@ -350,13 +348,13 @@ abstract class BuildPublishPlugin : Plugin { apiTokenFile: RegularFileProperty, channels: SetProperty, buildVariant: BuildVariant, - outputFileProvider: Provider, + apkOutputFileProvider: Provider, ) { register( "$SLACK_DISTRIBUTION_UPLOAD_TASK_PREFIX${buildVariant.capitalizedName()}", SlackDistributionTask::class.java, ) { - it.buildVariantOutputFile.set(outputFileProvider) + it.buildVariantOutputFile.set(apkOutputFileProvider) it.apiTokenFile.set(apiTokenFile) it.channels.set(channels) } @@ -474,7 +472,7 @@ abstract class BuildPublishPlugin : Plugin { AppCenterDistributionTask::class.java, ) { it.tagBuildFile.set(params.tagBuildProvider) - it.buildVariantOutputFile.set(params.buildVariantOutputFileProvider) + it.buildVariantOutputFile.set(params.apkOutputFileProvider) it.changelogFile.set(params.changelogFileProvider) it.apiTokenFile.set(config.apiTokenFile) it.ownerName.set(config.ownerName) @@ -498,7 +496,7 @@ abstract class BuildPublishPlugin : Plugin { PlayDistributionTask::class.java, ) { it.tagBuildFile.set(params.tagBuildProvider) - it.buildVariantOutputFile.set(params.buildVariantOutputFileProvider) + it.buildVariantOutputFile.set(params.bundleOutputFileProvider) it.apiTokenFile.set(config.apiTokenFile) it.appId.set(config.appId) it.trackId.set(config.trackId) @@ -584,23 +582,22 @@ private fun AppDistributionExtension.configure( private data class OutputProviders( val versionName: Provider, val versionCode: Provider, - val outputFileName: Provider, + val apkOutputFileName: Provider, ) private data class AppCenterDistributionTaskParams( val config: AppCenterDistributionConfig, val buildVariant: BuildVariant, val changelogFileProvider: Provider, - val buildVariantOutputFileProvider: Provider, + val apkOutputFileProvider: Provider, val tagBuildProvider: Provider, val outputConfig: OutputConfig, ) - private data class PlayTaskParams( val config: PlayConfig, val buildVariant: BuildVariant, - val buildVariantOutputFileProvider: Provider, + val bundleOutputFileProvider: Provider, val tagBuildProvider: Provider, val outputConfig: OutputConfig, ) @@ -614,7 +611,7 @@ private fun mapToVersionCode(tagBuildFile: RegularFile): Int { } } -private fun mapToOutputFileName( +private fun mapToOutputApkFileName( tagBuildFile: RegularFile, outputFileName: String, baseFileName: String?, @@ -626,15 +623,8 @@ private fun mapToOutputFileName( val versionName = tagBuild.buildVariant val versionCode = tagBuild.buildNumber "$baseFileName-$versionName-vc$versionCode-$formattedDate.apk" - } else if (file.exists() && outputFileName.endsWith(".aab")) { - val tagBuild = fromJson(file) - val versionName = tagBuild.buildVariant - val versionCode = tagBuild.buildNumber - "$baseFileName-$versionName-vc$versionCode-$formattedDate.aab" } else if (!file.exists() && outputFileName.endsWith(".apk")) { "$baseFileName-$formattedDate.apk" - } else if (!file.exists() && outputFileName.endsWith(".aab")) { - "$baseFileName-$formattedDate.aab" } else { createDefaultOutputFileName(baseFileName, outputFileName) } @@ -660,20 +650,13 @@ private fun mapToVersionName( } } -private fun Project.mapToOutputFile( +private fun Project.mapToOutputApkFile( buildVariant: BuildVariant, fileName: String, ): Provider { - return if (fileName.endsWith("aab")) { - project.tasks.withType(PackageBundleTask::class.java) - .firstOrNull { it.variantName == buildVariant.name } - ?.bundleFile - ?: throw GradleException("no output for variant ${buildVariant.name}") - } else { - project.tasks.withType(PackageAndroidArtifact::class.java) - .firstOrNull { it.variantName == buildVariant.name } - ?.outputDirectory - ?.map { directory -> directory.file(fileName) } - ?: throw GradleException("no output for variant ${buildVariant.name}") - } + return project.tasks.withType(PackageAndroidArtifact::class.java) + .firstOrNull { it.variantName == buildVariant.name } + ?.outputDirectory + ?.map { directory -> directory.file(fileName) } + ?: throw GradleException("no output for variant ${buildVariant.name}") } diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/PlayDistributionTask.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/PlayDistributionTask.kt index ba83483..24935b7 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/PlayDistributionTask.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/PlayDistributionTask.kt @@ -5,7 +5,6 @@ import org.gradle.api.GradleException import org.gradle.api.file.RegularFileProperty import org.gradle.api.plugins.BasePlugin import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Optional @@ -14,83 +13,85 @@ import org.gradle.api.tasks.options.Option import org.gradle.workers.WorkQueue import org.gradle.workers.WorkerExecutor import ru.kode.android.build.publish.plugin.enity.mapper.fromJson -import ru.kode.android.build.publish.plugin.extension.config.MAX_REQUEST_COUNT -import ru.kode.android.build.publish.plugin.extension.config.MAX_REQUEST_DELAY_MS -import ru.kode.android.build.publish.plugin.task.appcenter.work.AppCenterUploadWork import ru.kode.android.build.publish.plugin.task.play.work.PlayUploadWork -import ru.kode.android.build.publish.plugin.util.capitalized import javax.inject.Inject + +/** + * Task to publish app at given release track in google play console with set priority + * Contains basic functionality, for the extensions reference to original implementation: + * https://github.com/Triple-T/gradle-play-publisher + */ abstract class PlayDistributionTask - @Inject - constructor( - private val workerExecutor: WorkerExecutor, - ) : DefaultTask() { - init { - description = "Task to send apk to Google Play" - group = BasePlugin.BUILD_GROUP - } +@Inject +constructor( + private val workerExecutor: WorkerExecutor, +) : DefaultTask() { + init { + description = "Task to send apk to Google Play" + group = BasePlugin.BUILD_GROUP + } - @get:InputFile - @get:Option( - option = "buildVariantOutputFile", - description = "Artifact output file (absolute path is expected)", - ) - abstract val buildVariantOutputFile: RegularFileProperty + @get:InputFile + @get:Option( + option = "buildVariantOutputFile", + description = "Artifact output file (absolute path is expected)", + ) + abstract val buildVariantOutputFile: RegularFileProperty - @get:InputFile - @get:Option(option = "tagBuildFile", description = "Json contains info about tag build") - abstract val tagBuildFile: RegularFileProperty + @get:InputFile + @get:Option(option = "tagBuildFile", description = "Json contains info about tag build") + abstract val tagBuildFile: RegularFileProperty - @get:InputFile - @get:Option( - option = "apiTokenFile", - description = "API token for google play console", - ) - abstract val apiTokenFile: RegularFileProperty + @get:InputFile + @get:Option( + option = "apiTokenFile", + description = "API token for google play console", + ) + abstract val apiTokenFile: RegularFileProperty - @get:Input - @get:Option( - option = "appId", - description = "appId from Play Console", - ) - abstract val appId: Property + @get:Input + @get:Option( + option = "appId", + description = "appId from Play Console", + ) + abstract val appId: Property - @get:Input - @get:Option( - option = "trackId", - description = "Track name of target app. Defaults to internal", - ) - abstract val trackId: Property + @get:Input + @get:Option( + option = "trackId", + description = "Track name of target app. Defaults to internal", + ) + abstract val trackId: Property - @get:Input - @get:Optional - @get:Option( - option = "updatePriority", - description = "Update priority (0..5)", - ) - abstract val updatePriority: Property + @get:Input + @get:Optional + @get:Option( + option = "updatePriority", + description = "Update priority (0..5)", + ) + abstract val updatePriority: Property - @TaskAction - fun upload() { - val outputFile = buildVariantOutputFile.asFile.get() - if (outputFile.extension != "aab") throw GradleException("file ${outputFile.path} is not bundle") - val tag = fromJson(tagBuildFile.asFile.get()) - val releaseName = "${tag.name}(${tag.buildVersion}.${tag.buildNumber})" - val apiTokenFile = apiTokenFile.asFile.get() - val workQueue: WorkQueue = workerExecutor.noIsolation() - val trackId = trackId.orNull ?: "internal" - val appId = appId.get() - val updatePriority = updatePriority.orNull ?: 0 + @TaskAction + fun upload() { + val outputFile = buildVariantOutputFile.asFile.get() + if (outputFile.extension != "aab") throw GradleException("file ${outputFile.path} is not bundle") + val tag = fromJson(tagBuildFile.asFile.get()) + val releaseName = "${tag.name}(${tag.buildVersion}.${tag.buildNumber})" + val apiTokenFile = apiTokenFile.asFile.get() + val workQueue: WorkQueue = workerExecutor.noIsolation() + val trackId = trackId.orNull ?: "internal" + val appId = appId.get() + val updatePriority = updatePriority.orNull ?: 0 - workQueue.submit(PlayUploadWork::class.java) { parameters -> - parameters.appId.set(appId) - parameters.apiToken.set(apiTokenFile) - parameters.trackId.set(trackId) - parameters.updatePriority.set(updatePriority) - parameters.releaseName.set(releaseName) - parameters.outputFile.set(outputFile) - } + workQueue.submit(PlayUploadWork::class.java) { parameters -> + parameters.appId.set(appId) + parameters.apiToken.set(apiTokenFile) + parameters.trackId.set(trackId) + parameters.updatePriority.set(updatePriority) + parameters.releaseName.set(releaseName) + parameters.outputFile.set(outputFile) } } +} diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/DefaultPlayPublisher.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/DefaultPlayPublisher.kt index 6b9ceae..703f827 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/DefaultPlayPublisher.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/DefaultPlayPublisher.kt @@ -7,13 +7,10 @@ import com.google.api.client.http.FileContent import com.google.api.client.json.gson.GsonFactory import com.google.api.services.androidpublisher.AndroidPublisher import com.google.api.services.androidpublisher.model.Apk -import com.google.api.services.androidpublisher.model.AppDetails import com.google.api.services.androidpublisher.model.Bundle import com.google.api.services.androidpublisher.model.DeobfuscationFilesUploadResponse import com.google.api.services.androidpublisher.model.ExpansionFile -import com.google.api.services.androidpublisher.model.Image import com.google.api.services.androidpublisher.model.InAppProduct -import com.google.api.services.androidpublisher.model.Listing import com.google.api.services.androidpublisher.model.Track import java.io.File import kotlin.math.roundToInt @@ -53,36 +50,6 @@ internal class DefaultPlayPublisher( publisher.edits().validate(appId, id).execute() } - override fun getAppDetails(editId: String): AppDetails { - return publisher.edits().details().get(appId, editId).execute() - } - - override fun getListings(editId: String): List { - return publisher.edits().listings().list(appId, editId).execute()?.listings.orEmpty() - } - - override fun getImages(editId: String, locale: String, type: String): List { - val response = publisher.edits().images().list(appId, editId, locale, type).execute() - return response?.images.orEmpty() - } - - override fun updateDetails(editId: String, details: AppDetails) { - publisher.edits().details().update(appId, editId, details).execute() - } - - override fun updateListing(editId: String, locale: String, listing: Listing) { - publisher.edits().listings().update(appId, editId, locale, listing).execute() - } - - override fun deleteImages(editId: String, locale: String, type: String) { - publisher.edits().images().deleteall(appId, editId, locale, type).execute() - } - - override fun uploadImage(editId: String, locale: String, type: String, image: File) { - val content = FileContent(MIME_TYPE_IMAGE, image) - publisher.edits().images().upload(appId, editId, locale, type, content).execute() - } - override fun getTrack(editId: String, track: String): Track { return try { publisher.edits().tracks().get(appId, editId, track).execute() diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/InternalPlayPublisher.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/InternalPlayPublisher.kt index 2690433..db15762 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/InternalPlayPublisher.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/InternalPlayPublisher.kt @@ -1,11 +1,8 @@ package ru.kode.android.build.publish.plugin.task.play.publisher import com.google.api.services.androidpublisher.model.Apk -import com.google.api.services.androidpublisher.model.AppDetails import com.google.api.services.androidpublisher.model.Bundle import com.google.api.services.androidpublisher.model.DeobfuscationFilesUploadResponse -import com.google.api.services.androidpublisher.model.Image -import com.google.api.services.androidpublisher.model.Listing import com.google.api.services.androidpublisher.model.Track import ru.kode.android.build.publish.plugin.task.play.PlayPublisher import java.io.File @@ -14,20 +11,6 @@ import java.io.IOException internal interface InternalPlayPublisher : PlayPublisher { val appId: String - fun getAppDetails(editId: String): AppDetails - - fun getListings(editId: String): List- - fun getImages(editId: String, locale: String, type: String): List - - fun updateDetails(editId: String, details: AppDetails) - - fun updateListing(editId: String, locale: String, listing: Listing) - - fun deleteImages(editId: String, locale: String, type: String) - - fun uploadImage(editId: String, locale: String, type: String, image: File) - fun getTrack(editId: String, track: String): Track fun listTracks(editId: String): List diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/PublisherModels.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/PublisherModels.kt index 4b34a59..ef59cf5 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/PublisherModels.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/PublisherModels.kt @@ -7,8 +7,8 @@ package ru.kode.android.build.publish.plugin.task.play.publisher * [here](https://developers.google.com/android-publisher/api-ref/edits/tracks). */ enum class ReleaseStatus( - /** The API name of the status. */ - val publishedName: String, + /** The API name of the status. */ + val publishedName: String, ) { /** The release is live. */ COMPLETED("completed"), @@ -30,8 +30,8 @@ enum class ReleaseStatus( * [here](https://github.com/Triple-T/gradle-play-publisher#handling-version-conflicts). */ enum class ResolutionStrategy( - /** The API name of the strategy. */ - val publishedName: String, + /** The API name of the strategy. */ + val publishedName: String, ) { /** Conflicts should be automagically resolved. */ AUTO("auto"), diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/Responses.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/Responses.kt index 34d4cdb..8eeaa28 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/Responses.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/publisher/Responses.kt @@ -4,66 +4,66 @@ import com.google.api.client.googleapis.json.GoogleJsonResponseException /** Response for an app details request. */ data class GppAppDetails internal constructor( - /** The default language. */ - val defaultLocale: String?, - /** Developer contact email. */ - val contactEmail: String?, - /** Developer contact phone. */ - val contactPhone: String?, - /** Developer contact website. */ - val contactWebsite: String?, + /** The default language. */ + val defaultLocale: String?, + /** Developer contact email. */ + val contactEmail: String?, + /** Developer contact phone. */ + val contactPhone: String?, + /** Developer contact website. */ + val contactWebsite: String?, ) /** Response for an app listing request. */ data class GppListing internal constructor( - /** The listing's language. */ - val locale: String, - /** The app description. */ - val fullDescription: String?, - /** The app tagline. */ - val shortDescription: String?, - /** The app title. */ - val title: String?, - /** The app promo url. */ - val video: String?, + /** The listing's language. */ + val locale: String, + /** The app description. */ + val fullDescription: String?, + /** The app tagline. */ + val shortDescription: String?, + /** The app title. */ + val title: String?, + /** The app promo url. */ + val video: String?, ) /** Response for an app graphic request. */ data class GppImage internal constructor( - /** The image's download URL. */ - val url: String, - /** The image's SHA256 hash. */ - val sha256: String, + /** The image's download URL. */ + val url: String, + /** The image's SHA256 hash. */ + val sha256: String, ) /** Response for a track release note request. */ data class ReleaseNote internal constructor( - /** The release note's track. */ - val track: String, - /** The release note's language. */ - val locale: String, - /** The release note. */ - val contents: String, + /** The release note's track. */ + val track: String, + /** The release note's language. */ + val locale: String, + /** The release note. */ + val contents: String, ) /** Response for an edit request. */ sealed class EditResponse { /** Response for a successful edit request. */ data class Success internal constructor( - /** The id of the edit in question. */ - val id: String, + /** The id of the edit in question. */ + val id: String, ) : EditResponse() /** Response for an unsuccessful edit request. */ data class Failure internal constructor( - private val e: GoogleJsonResponseException, + private val e: GoogleJsonResponseException, ) : EditResponse() { /** @return true if the app wasn't found in the Play Console, false otherwise */ fun isNewApp(): Boolean = e has "applicationNotFound" /** @return true if the provided edit is invalid for any reason, false otherwise */ fun isInvalidEdit(): Boolean = - e has "editAlreadyCommitted" || e has "editNotFound" || e has "editExpired" + e has "editAlreadyCommitted" || e has "editNotFound" || e has "editExpired" /** @return true if the user doesn't have permission to access this app, false otherwise */ fun isUnauthorized(): Boolean = e.statusCode == 401 @@ -83,11 +83,11 @@ sealed class CommitResponse { /** Response for an unsuccessful commit request. */ data class Failure internal constructor( - private val e: GoogleJsonResponseException, + private val e: GoogleJsonResponseException, ) : CommitResponse() { /** @return true if the changes cannot be sent for review, false otherwise */ fun failedToSendForReview(): Boolean = - e has "badRequest" && e.details.message.orEmpty().contains("changesNotSentForReview") + e has "badRequest" && e.details.message.orEmpty().contains("changesNotSentForReview") /** Cleanly rethrows the error. */ fun rethrow(suppressed: Failure? = null): Nothing { @@ -102,23 +102,23 @@ sealed class CommitResponse { /** Response for an internal sharing artifact upload. */ data class UploadInternalSharingArtifactResponse internal constructor( - /** The response's full JSON payload. */ - val json: String, + /** The response's full JSON payload. */ + val json: String, - /** The download URL of the uploaded artifact. */ - val downloadUrl: String, + /** The download URL of the uploaded artifact. */ + val downloadUrl: String, ) /** Response for a product request. */ data class GppProduct internal constructor( - /** The product ID. */ - val sku: String, - /** The response's full JSON payload. */ - val json: String, + /** The product ID. */ + val sku: String, + /** The response's full JSON payload. */ + val json: String, ) /** Response for a product update request. */ data class UpdateProductResponse internal constructor( - /** @return true if the product doesn't exist and needs to be created, false otherwise. */ - val needsCreating: Boolean, + /** @return true if the product doesn't exist and needs to be created, false otherwise. */ + val needsCreating: Boolean, ) diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/DefaultEditManager.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/DefaultEditManager.kt index 29cafe2..72e8f50 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/DefaultEditManager.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/DefaultEditManager.kt @@ -1,14 +1,8 @@ package ru.kode.android.build.publish.plugin.task.play.track import com.google.api.client.googleapis.json.GoogleJsonResponseException -import com.google.api.services.androidpublisher.model.AppDetails -import com.google.api.services.androidpublisher.model.Listing import org.slf4j.LoggerFactory -import ru.kode.android.build.publish.plugin.task.play.publisher.GppAppDetails -import ru.kode.android.build.publish.plugin.task.play.publisher.GppImage -import ru.kode.android.build.publish.plugin.task.play.publisher.GppListing import ru.kode.android.build.publish.plugin.task.play.publisher.InternalPlayPublisher -import ru.kode.android.build.publish.plugin.task.play.publisher.ReleaseNote import ru.kode.android.build.publish.plugin.task.play.publisher.ReleaseStatus import ru.kode.android.build.publish.plugin.task.play.publisher.ResolutionStrategy import ru.kode.android.build.publish.plugin.task.play.publisher.has @@ -19,88 +13,6 @@ internal class DefaultEditManager( private val tracks: TrackManager, private val editId: String, ) : EditManager { - override fun getAppDetails(): GppAppDetails { - val details = publisher.getAppDetails(editId) - return GppAppDetails( - details.defaultLanguage, - details.contactEmail, - details.contactPhone, - details.contactWebsite - ) - } - - override fun getListings(): List { - return publisher.getListings(editId).map { - GppListing( - it.language, - it.fullDescription, - it.shortDescription, - it.title, - it.video - ) - } - } - - override fun getImages(locale: String, type: String): List { - return publisher.getImages(editId, locale, type).map { - GppImage(it.url + HIGH_RES_IMAGE_REQUEST, it.sha256) - } - } - - override fun findMaxAppVersionCode(): Long { - return tracks.findHighestTrack()?.releases.orEmpty() - .flatMap { it.versionCodes.orEmpty() } - .maxOrNull() ?: 1 - } - - override fun findLeastStableTrackName(): String? { - return tracks.findHighestTrack()?.track - } - - override fun getReleaseNotes(): List { - return tracks.getReleaseNotes().map { (track, notes) -> - notes.map { ReleaseNote(track, it.language, it.text) } - }.flatten() - } - - override fun publishAppDetails( - defaultLocale: String?, - contactEmail: String?, - contactPhone: String?, - contactWebsite: String?, - ) { - publisher.updateDetails(editId, AppDetails().apply { - this.defaultLanguage = defaultLocale - this.contactEmail = contactEmail - this.contactPhone = contactPhone - this.contactWebsite = contactWebsite - }) - } - - override fun publishListing( - locale: String, - title: String?, - shortDescription: String?, - fullDescription: String?, - video: String?, - ) { - publisher.updateListing(editId, locale, Listing().apply { - this.title = title - this.shortDescription = shortDescription - this.fullDescription = fullDescription - this.video = video - }) - } - - override fun publishImages(locale: String, type: String, images: List) { - publisher.deleteImages(editId, locale, type) - for (image in images) { - println("Uploading $locale listing graphic for type '$type': ${image.name}") - // These can't be uploaded in parallel because order matters - publisher.uploadImage(editId, locale, type, image) - } - } - override fun promoteRelease( promoteTrackName: String, fromTrackName: String, @@ -169,17 +81,6 @@ internal class DefaultEditManager( )) } - private fun uploadMappingFile(versionCode: Int, mappingFile: File?) { - if (mappingFile != null && mappingFile.length() > 0) { - publisher.uploadDeobfuscationFile(editId, mappingFile, versionCode, "proguard") - } - } - - private fun Int.attachObb(type: String, versionCode: Int) { - println("Attaching $type OBB ($this) to APK $versionCode") - publisher.attachObb(editId, type, versionCode, this) - } - private fun handleUploadFailures( e: GoogleJsonResponseException, strategy: ResolutionStrategy, @@ -217,5 +118,3 @@ internal class DefaultEditManager( throw e } } - -private const val HIGH_RES_IMAGE_REQUEST = "=h16383" // Max res: 2^14 - 1 diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/EditManager.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/EditManager.kt index 5ba181d..5a773d3 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/EditManager.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/EditManager.kt @@ -1,44 +1,17 @@ package ru.kode.android.build.publish.plugin.task.play.track -import ru.kode.android.build.publish.plugin.task.play.PlayPublisher -import ru.kode.android.build.publish.plugin.task.play.publisher.GppAppDetails -import ru.kode.android.build.publish.plugin.task.play.publisher.GppImage -import ru.kode.android.build.publish.plugin.task.play.publisher.GppListing -import ru.kode.android.build.publish.plugin.task.play.publisher.ReleaseNote import ru.kode.android.build.publish.plugin.task.play.publisher.ReleaseStatus import ru.kode.android.build.publish.plugin.task.play.publisher.ResolutionStrategy import java.io.File -import java.util.ServiceLoader interface EditManager { - fun getAppDetails(): GppAppDetails - fun getListings(): List - fun getImages(locale: String, type: String): List - fun findMaxAppVersionCode(): Long - fun findLeastStableTrackName(): String? - fun getReleaseNotes(): List - fun publishAppDetails( - defaultLocale: String?, - contactEmail: String?, - contactPhone: String?, - contactWebsite: String?, - ) - - fun publishListing( - locale: String, - title: String?, - shortDescription: String?, - fullDescription: String?, - video: String?, - ) - fun publishImages(locale: String, type: String, images: List) fun promoteRelease( promoteTrackName: String, fromTrackName: String, releaseStatus: ReleaseStatus?, releaseName: String?, - releaseNotes: Map?, + releaseNotes: Map?, userFraction: Double?, updatePriority: Int?, retainableArtifacts: List?, @@ -56,21 +29,9 @@ interface EditManager { trackName: String, releaseStatus: ReleaseStatus?, releaseName: String?, - releaseNotes: Map?, + releaseNotes: Map?, userFraction: Double?, updatePriority: Int?, retainableArtifacts: List?, ) - - interface Factory { - fun create(publisher: PlayPublisher, editId: String): EditManager - } - - companion object { - operator fun invoke( - publisher: PlayPublisher, - editId: String, - ): EditManager = ServiceLoader.load(Factory::class.java).last() - .create(publisher, editId) - } } diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/TrackManager.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/TrackManager.kt index fa614da..b38a2f1 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/TrackManager.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/track/TrackManager.kt @@ -7,10 +7,6 @@ import ru.kode.android.build.publish.plugin.task.play.publisher.InternalPlayPubl import ru.kode.android.build.publish.plugin.task.play.publisher.ReleaseStatus internal interface TrackManager { - fun findHighestTrack(): Track? - - fun getReleaseNotes(): Map> - fun update(config: UpdateConfig) fun promote(config: PromoteConfig) @@ -43,27 +39,6 @@ internal class DefaultTrackManager( private val publisher: InternalPlayPublisher, private val editId: String, ) : TrackManager { - override fun findHighestTrack(): Track? { - return publisher.listTracks(editId).maxByOrNull { - it.releases.orEmpty().flatMap { it.versionCodes.orEmpty() }.maxOrNull() ?: 0 - } - } - - override fun getReleaseNotes(): Map> { - val releaseNotes = mutableMapOf>() - - val tracks = publisher.listTracks(editId) - for (track in tracks) { - val notes = track.releases?.maxByOrNull { - it.versionCodes?.maxOrNull() ?: Long.MIN_VALUE - }?.releaseNotes.orEmpty() - - releaseNotes[track.track] = notes - } - - return releaseNotes - } - override fun update(config: TrackManager.UpdateConfig) { val track = if (config.didPreviousBuildSkipCommit) { createTrackForSkippedCommit(config) @@ -114,7 +89,7 @@ internal class DefaultTrackManager( for (release in track.releases) { if (release.status == config.base.releaseStatus.orDefault().publishedName) { release.mergeChanges( - release.versionCodes.orEmpty() + config.versionCodes, config.base) + release.versionCodes.orEmpty() + config.versionCodes, config.base) } } } else { @@ -152,8 +127,8 @@ internal class DefaultTrackManager( if (!releaseNotes.isNullOrEmpty()) return val previousRelease = publisher.getTrack(editId, trackName) - .releases.orEmpty() - .maxByOrNull { it.versionCodes.orEmpty().maxOrNull() ?: 1 } + .releases.orEmpty() + .maxByOrNull { it.versionCodes.orEmpty().maxOrNull() ?: 1 } releaseNotes = previousRelease?.releaseNotes } @@ -227,11 +202,11 @@ internal class DefaultTrackManager( } private fun ReleaseStatus.isRollout() = - this == ReleaseStatus.IN_PROGRESS || this == ReleaseStatus.HALTED + this == ReleaseStatus.IN_PROGRESS || this == ReleaseStatus.HALTED private fun TrackRelease.isRollout() = - status == ReleaseStatus.IN_PROGRESS.publishedName || - status == ReleaseStatus.HALTED.publishedName + status == ReleaseStatus.IN_PROGRESS.publishedName || + status == ReleaseStatus.HALTED.publishedName private fun ReleaseStatus?.orDefault() = this ?: DEFAULT_RELEASE_STATUS diff --git a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/work/PlayUploadWork.kt b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/work/PlayUploadWork.kt index 30dfd84..3de6c3d 100644 --- a/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/work/PlayUploadWork.kt +++ b/plugin-build/plugin/src/main/java/ru/kode/android/build/publish/plugin/task/play/work/PlayUploadWork.kt @@ -3,7 +3,6 @@ package ru.kode.android.build.publish.plugin.task.play.work import org.gradle.api.file.RegularFileProperty import org.gradle.api.logging.Logging import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty import org.gradle.workers.WorkAction import org.gradle.workers.WorkParameters import ru.kode.android.build.publish.plugin.task.play.publisher.DefaultPlayPublisher @@ -41,11 +40,18 @@ abstract class PlayUploadWork : WorkAction { logger.info("Step 1/3: Requesting track edit...") val editId = when (val result = publisher.insertEdit()) { is EditResponse.Success -> result.id - is EditResponse.Failure -> null + is EditResponse.Failure -> { + if (result.isNewApp()) { + logger.error("Error response: app does not exist") + } else { + logger.error("Error response: $result") + } + null + } } if (editId == null) { - logger.error("Failed to fetch edit id to upload bundle. Check your credentials") + logger.error("Failed to fetch edit id to upload bundle") return } @@ -57,7 +63,7 @@ abstract class PlayUploadWork : WorkAction { val versionCode = editManager.uploadBundle(file, ResolutionStrategy.IGNORE) if (versionCode == null) { - logger.error("Failed to upload bundle. Check your credentials") + logger.error("Failed to upload bundle") return }