rustore-publish-gradle-plugin icon indicating copy to clipboard operation
rustore-publish-gradle-plugin copied to clipboard

Ошибка сериализации publishType при создании черновика с ручной публикацией

Open xlxoxlx22 opened this issue 7 months ago • 5 comments

Привет! При выполнении команды публикации ./gradlew app:publishRustore<name>RustoreRelease возникает ошибка с обработкой параметра publishType.

  • Все настройки build.gradle и тд. выполнены согласно readme: https://github.com/cianru/rustore-publish-gradle-plugin
  • В build.gradle параметр задавался несколькими способами:
    • publishType = 'manual'
    • publishType = 'MANUAL'
    • publishType = "manual"
    • publishType = "MANUAL"
    • publishType = ru.cian.rustore.publish.PublishType.MANUAL
    • setPublishType(ru.cian.rustore.publish.PublishType.MANUAL)

Итоговый BuildOutput:

publishRustore<name>RustoreRelease FAILED
Rustore Publishing API: 1/6. Prepare input config
Rustore Publishing API: Build File Directory: /<folder>/build/outputs/apk/<name>Rustore/release
Rustore Publishing API: Found build file: `<version>-rustore-release.apk`
Rustore Publishing API: 2/6. Create signature
Rustore Publishing API: 3/6. Get Access Token
Rustore Publishing API: 4/6. Create App Draft
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected an int but was BEGIN_OBJECT at line 1 column 76 path $.body
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:397)
	at com.google.gson.Gson.fromJson(Gson.java:1227)
	at com.google.gson.Gson.fromJson(Gson.java:1137)
	at com.google.gson.Gson.fromJson(Gson.java:1075)
	at ru.cian.rustore.publish.service.RustoreServiceImpl.createDraft(RustoreServiceImpl.kt:310)
	at ru.cian.rustore.publish.RustorePublishTask.action(RustorePublishTask.kt:210)
// ...

Смотрел в исходниках, по шагам из BuildOutput:

  1. RustorePublishTask
val appVersionId = rustoreService.createDraft(
            token = token,
            applicationId = config.applicationId,
            whatsNew = config.releaseNotes?.first()?.newFeatures ?: "",
            publishType = config.publishType.name,
        )
  1. RustoreServiceImpl, где вроде бы и происходит само падение при работе с gson.
override fun createDraft(
        token: String,
        applicationId: String,
        whatsNew: String,
        publishType: String,
    ): Int {
        val bodyRequest = AppDraftRequest(
            whatsNew = whatsNew,
            publishType = publishType,
        )

        logger.i("""
            curl --location --request POST \
            $baseEntryPoint/public/v1/application/$applicationId/version \
            --header 'Content-Type: application/json' \
            --header 'Public-Token: $token' \
            --data-raw '{
                "whatsNew": "$whatsNew",
                "publishType": "$publishType"
            }'            
        """.trimIndent())

        val response = httpClient.post<AppDraftResponse>(
            url = "$baseEntryPoint/public/v1/application/$applicationId/version",
            body = gson.toJson(bodyRequest).toRequestBody(),
            headers = mapOf(
                "Content-Type" to "application/json",
                "Public-Token" to token,
            ),
        )
// ...
  1. AppDraftRequest
internal data class AppDraftRequest(
    @SerializedName("whatsNew")
    val whatsNew: String,
    @SerializedName("publishType")
    val publishType: String,
)

Пока версия только такая, что ошибка возникает именно при десериализации ответа, а не при отправке запроса. Поэтому проблема скорее всего в структуре возвращаемых данных или в их несоответствии ожидаемому типу.

xlxoxlx22 avatar Apr 25 '25 11:04 xlxoxlx22

@xlxoxlx22 Привет. Да, судя по всему дело в ответе сервера. Не смог воспроизвести. Возможно у вас уникальный случай, например в типе или выданных разрешениях аккаунта от имени которого делается публикация. К сожалению у нас нет технической возможности исследовать все возможные кейсы. Давайте разберемся вместе.

Попробуйте пожалуйста проделать тоже самое, но добавить к gradle команде ключик --info. В лог выведутся curl примеры запросов. Попробуйте его дернуть руками через commandline и покажите пожалуйста что выдаст предварительно скрыв конфеденциальную информацию, если она будет.

cosic avatar Apr 29 '25 08:04 cosic

@cosic Привет, выполнил команду с --info, результат следующий:

Rustore Publishing API: 2/6. Create signature
Rustore Publishing API: 3/6. Get Access Token
INFO, Rustore Publishing API: curl --location --request POST \
https://public-api.rustore.ru/public/auth/ \
--header 'Content-Type: application/json' \
--data-raw '{
   "keyId": "<keyId>",
   "timestamp": "2025-05-05T11:03:00.6781630+03:00",
   "signature": "<code>"
}'            
Rustore Publishing API: 4/6. Create App Draft
INFO, Rustore Publishing API: curl --location --request POST \
https://public-api.rustore.ru/public/v1/application/<appId>/version \
--header 'Content-Type: application/json' \
--header 'Public-Token: <token>' \
--data-raw '{
   "whatsNew": "",
   "publishType": "MANUAL"
}'            
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected an int but was BEGIN_OBJECT at line 1 column 76 path $.body
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:397)
	at com.google.gson.Gson.fromJson(Gson.java:1227)
	at com.google.gson.Gson.fromJson(Gson.java:1137)
	at com.google.gson.Gson.fromJson(Gson.java:1075)
	at ru.cian.rustore.publish.service.RustoreServiceImpl.createDraft(RustoreServiceImpl.kt:310)
	at ru.cian.rustore.publish.RustorePublishTask.action(RustorePublishTask.kt:210)
// ...

В build.gradle сейчас следующие настройки:

<name>RustoreRelease {
  instances {
    {
	credentialsPath = "$projectDir/rustore-credentials-release.json"
	publishType = ru.cian.rustore.publish.PublishType.MANUAL
    }
  }
}

xlxoxlx22 avatar May 05 '25 08:05 xlxoxlx22

@cosic Привет! Есть ли какие-нибудь идеи или может еще данные требуются?

xlxoxlx22 avatar May 14 '25 09:05 xlxoxlx22

@xlxoxlx22 Привет. Обратите внимание, я просил

Попробуйте пожалуйста проделать тоже самое, но добавить к gradle команде ключик --info. В лог выведутся curl примеры запросов. Попробуйте его дернуть руками через commandline и покажите...

Сложно воспроизводить кейсы на проде, пришлось ждать релиза и пробовать самостоятельно. В общем, в вашем случае RuStore API выпадает следующую ошибку:

{"code":"ERROR","message":"request size must be between 1 and 5000","body":{"PROPERTY":"whatsNew","METHOD":"createVersion","PARAMETER":"request"},"timestamp":"2025-05-19T01:23:45.281074218+03:00"}%

что говорит об обязательности заполненого whatsNew параметра, т.е. Release Notes с сборки.

Т.е. вам нужно использовать параметр плагина releaseNotes, а мне обработать выпадающую ошибку в рамках этого issue. К сожалению в своей документации они не приводят примеры с ошибками, приходится добывать самостоятельно. И появился повод пересмотреть документацию.

cosic avatar May 18 '25 22:05 cosic

@cosic Привет, насколько помню я так и сделал, к команде добавил ключ --info. Возможно не ту часть данных скинул, конечно.

Но как бы то не было, добавил параметр releaseNotes и теперь сборка начала подгружаться в RuStore.

Спасибо!

xlxoxlx22 avatar May 20 '25 11:05 xlxoxlx22