diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml
index f082593..c3aac3c 100644
--- a/.github/workflows/codestyle.yml
+++ b/.github/workflows/codestyle.yml
@@ -11,10 +11,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Set up JDK 11
+ - name: Set up JDK 17
uses: actions/setup-java@v1
with:
- java-version: 11
+ java-version: 17
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run detekt checks
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index b5154eb..8a3eb6b 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -15,10 +15,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Set up JDK 11
+ - name: Set up JDK 17
uses: actions/setup-java@v1
with:
- java-version: 11
+ java-version: 17
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build plugin
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index bf01284..f25fb85 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -11,15 +11,15 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
- kotlin-version: [1.4.21, 1.5.30, 1.6.10]
+ kotlin-version: [1.8.21, 1.9.21]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- - name: Set up JDK 11
+ - name: Set up JDK 17
uses: actions/setup-java@v1
with:
- java-version: 11
+ java-version: 17
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run tests with Gradle
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 697e4d2..e3aeed8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# 0.3.2
+
+##### Add
+* [issue#5](https://github.com/cianru/rustore-publish-gradle-plugin/issues/5) Support of serviceType plugin param.
+
# 0.3.1
##### Add
diff --git a/README.md b/README.md
index 3d2c428..046ad5e 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,13 @@
[//]: # (
)
-
+
RuStore Publishing
-![Version](https://img.shields.io/badge/GradlePortal-0.3.1-green.svg)
+![Version](https://img.shields.io/badge/GradlePortal-0.3.2-green.svg)
![Version](https://img.shields.io/badge/Gradle-8.*-pink.svg)
[![License](https://img.shields.io/github/license/srs/gradle-node-plugin.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
@@ -27,7 +27,6 @@ The plugin use [Rustore API](https://help.rustore.ru/rustore/for_developers/work
- [Using the `apply` method](#using-the-apply-method)
- [Configuring Plugin](#configuring-plugin)
- [Plugin usage](#plugin-usage)
-
# Features
@@ -58,10 +57,10 @@ The following features are not available on Rustore API side yet:
The Android Gradle Plugin often changes the Variant API,
so a different version of AGP corresponds to a specific version of the current plugin
-| AGP | Plugin |
-|-----|--------|
-| 7.+ | 0.2.2 |
-| 8.+ | 0.3.1 |
+| AGP | Plugin |
+|-----|----------------------------------------------------------------------------|
+| 7.+ | 0.2.2 |
+| 8.+ | [latest](https://github.com/cianru/rustore-publish-gradle-plugin/releases) |
# Adding the plugin to your project
@@ -76,6 +75,39 @@ plugins {
}
```
+
+Snapshot builds are also available
+___
+
+You'll need to add the Sonatype snapshots repository.
+Look for the actual version of the snapshot in the name of the opened `snapshot-` repository branch.
+
+For general integration add next snippet in `./settings.gradle`
+
+```kotlin
+pluginManagement {
+
+ resolutionStrategy {
+ eachPlugin {
+ if(requested.id.namespace == "ru.cian") {
+ useModule("ru.cian.rustore-plugin:rustore-publish-gradle-plugin:")
+ }
+ }
+ }
+
+ plugins {
+ id("ru.cian.rustore-publish-gradle-plugin") version rustorePublish apply false
+ }
+
+ repositories {
+ maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
+ }
+}
+```
+___
+
+
+
## Using the `apply` method
```groovy
@@ -93,7 +125,65 @@ apply plugin: 'com.android.application'
apply plugin: 'ru.cian.rustore-publish-gradle-plugin'
```
-## Configuring Plugin
+
+Snapshot builds are also available
+___
+
+You'll need to add the Sonatype snapshots repository.
+Look for the actual version of the snapshot in the name of the opened `snapshot-` repository branch.
+
+```groovy
+buildscript {
+ repositories {
+ maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
+ }
+
+ dependencies {
+ classpath "ru.cian.rustore-plugin:rustore-publish-gradle-plugin::-SNAPSHOT"
+ }
+}
+
+apply plugin: 'com.android.application'
+apply plugin: "ru.cian.rustore-publish-gradle-plugin"
+```
+___
+
+
+
+## Quickstart Plugin Configuration
+
+```kotlin
+rustorePublish {
+ instances {
+ create("release") {
+ /**
+ * Path to json file with RuStore credentials params (`company_id` and `client_secret`).
+ * How to get credentials see [[RU] Rustore API Getting Started](https://help.rustore.ru/rustore/for_developers/work_with_RuStore_API/authorization_rustore_api_1).
+ * Plugin credential json example:
+ * {
+ * "company_id": "",
+ * "client_secret": ""
+ * }
+ *
+ * Type: String (Optional)
+ * Default value: `null` (but plugin wait that you provide credentials by CLI params)
+ * CLI: `--credentialsPath`
+ */
+ credentialsPath = "$rootDir/rustore-credentials-release.json"
+
+ /**
+ * Path to build file if you would like to change default path. "null" means use standard path for "apk" and "aab" files.
+ * Type: String (Optional)
+ * Default value: `null`
+ * CLI: `--buildFile`
+ */
+ buildFile = "$rootDir/app/build/outputs/apk/release/app-release.apk"
+ }
+ }
+}
+```
+
+## Full Plugin Configuration
Kotlin
@@ -125,6 +215,16 @@ rustorePublish {
*/
buildFile = "$rootDir/app/build/outputs/apk/release/app-release.apk"
+ /**
+ * Type of mobile services used in application. Available values: [\"Unknown\", \"HMS\"].
+ * For more details see param `servicesType` in documentation " +
+ * https://www.rustore.ru/help/work-with-rustore-api/api-upload-publication-app/apk-file-upload/file-upload-apk/
+ * Type: ru.cian.rustore.publish.MobileServicesType (Optional)
+ * Default value: UNKNOWN
+ * CLI: `--mobileServicesType`
+ */
+ mobileServicesType = ru.cian.rustore.publish.MobileServicesType.UNKNOWN
+
/**
* Release Notes settings. For mote info see ReleaseNote param desc.
* Type: List (Optional)
@@ -171,6 +271,7 @@ rustorePublish {
release {
credentialsPath = "$rootDir/rustore-credentials-release.json"
buildFile = "$rootDir/app/build/outputs/apk/release/app-release.apk"
+ mobileServicesType = "Unknown"
releaseNotes = [
new ru.cian.rustore.publish.ReleaseNote(
"ru-RU",
@@ -191,6 +292,7 @@ the same by CLI
./gradlew assembleRelease publishRustoreRelease \
--credentialsPath="/sample-kotlin/rustore-credentials.json" \
--buildFile="/sample-kotlin/app/build/outputs/apk/release/app-release.apk" \
+ --mobileServicesType="Unknown" \
--releaseNotes="ru_RU:/home//str/project/release_notes_ru.txt"
```
CLI params are more priority than Plugin configuration params.
diff --git a/build.gradle.kts b/build.gradle.kts
index 4cd1ac1..9874f44 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,7 +13,7 @@ buildscript {
plugins {
alias(libs.plugins.kotlinJvm)
alias(libs.plugins.benManesVersions)
- alias(libs.plugins.gradleDoctor)
+// alias(libs.plugins.gradleDoctor)
}
allprojects {
@@ -23,46 +23,46 @@ allprojects {
}
}
-doctor {
- /**
- * Throw an exception when multiple Gradle Daemons are running.
- *
- * Windows is not supported yet, see https://github.com/runningcode/gradle-doctor/issues/84
- */
- disallowMultipleDaemons.set(true)
-
- /**
- * Warn when not using parallel GC. Parallel GC is faster for build type tasks and is no longer the default in Java 9+.
- */
- warnWhenNotUsingParallelGC.set(true)
-
- /**
- * Warn if using the Kotlin Compiler Daemon Fallback. The fallback is incredibly slow and should be avoided.
- * https://youtrack.jetbrains.com/issue/KT-48843
- */
- warnIfKotlinCompileDaemonFallback.set(true)
-
- /** Configuration properties relating to JAVA_HOME */
- javaHome {
- /**
- * Ensure that we are using JAVA_HOME to build with this Gradle.
- */
- ensureJavaHomeMatches.set(true)
- /**
- * Ensure we have JAVA_HOME set.
- */
- ensureJavaHomeIsSet.set(true)
- /**
- * Fail on any `JAVA_HOME` issues.
- */
- failOnError.set(true)
- /**
- * Extra message text, if any, to show with the Gradle Doctor message. This is useful if you have a wiki page or
- * other instructions that you want to link for developers on your team if they encounter an issue.
- */
- extraMessage.set("Gradle Doctor Issue!")
- }
-}
+//doctor {
+// /**
+// * Throw an exception when multiple Gradle Daemons are running.
+// *
+// * Windows is not supported yet, see https://github.com/runningcode/gradle-doctor/issues/84
+// */
+// disallowMultipleDaemons.set(true)
+//
+// /**
+// * Warn when not using parallel GC. Parallel GC is faster for build type tasks and is no longer the default in Java 9+.
+// */
+// warnWhenNotUsingParallelGC.set(true)
+//
+// /**
+// * Warn if using the Kotlin Compiler Daemon Fallback. The fallback is incredibly slow and should be avoided.
+// * https://youtrack.jetbrains.com/issue/KT-48843
+// */
+// warnIfKotlinCompileDaemonFallback.set(true)
+//
+// /** Configuration properties relating to JAVA_HOME */
+// javaHome {
+// /**
+// * Ensure that we are using JAVA_HOME to build with this Gradle.
+// */
+// ensureJavaHomeMatches.set(true)
+// /**
+// * Ensure we have JAVA_HOME set.
+// */
+// ensureJavaHomeIsSet.set(true)
+// /**
+// * Fail on any `JAVA_HOME` issues.
+// */
+// failOnError.set(true)
+// /**
+// * Extra message text, if any, to show with the Gradle Doctor message. This is useful if you have a wiki page or
+// * other instructions that you want to link for developers on your team if they encounter an issue.
+// */
+// extraMessage.set("Gradle Doctor Issue!")
+// }
+//}
configurations.all {
resolutionStrategy {
diff --git a/docs/screenshots/header_cian_rustore.png b/docs/screenshots/header_cian_rustore.png
new file mode 100644
index 0000000..89bf6b3
Binary files /dev/null and b/docs/screenshots/header_cian_rustore.png differ
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 26d2320..c2690ac 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,30 +11,32 @@ minSdkVersion = "21"
jvm = "17"
kotlin = "1.9.21"
detekt = "1.23.4"
-junitJupiter = "5.7.0"
+junitJupiter = "5.9.3"
androidGradlePlugin = "8.0.2"
-sampleRustorePlugin = "0.3.1-SNAPSHOT"
+sampleRustorePlugin = "0.3.2-SNAPSHOT"
[libraries]
appcompat = "androidx.appcompat:appcompat:1.6.1"
kotlinBom = { group = "org.jetbrains.kotlin", name = "kotlin-bom", version.ref = "kotlin" }
-kotlinDateTime = "org.jetbrains.kotlinx:kotlinx-datetime:0.4.0"
+kotlinDateTime = "org.jetbrains.kotlinx:kotlinx-datetime:0.5.0"
gson = "com.google.code.gson:gson:2.8.6"
-okHttp = "com.squareup.okhttp3:okhttp:4.9.1"
+okHttp = "com.squareup.okhttp3:okhttp:4.12.0"
androidGradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
+detektFormating = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
+detektRules = { module = "io.gitlab.arturbosch.detekt:detekt-rules-libraries", version.ref = "detekt" }
+
test-assertk = "com.willowtreeapps.assertk:assertk-jvm:0.23"
-test-hamcreast = "org.hamcrest:hamcrest:2.1"
-test-mockk = "io.mockk:mockk:1.10.3-jdk8"
+test-hamcreast = "org.hamcrest:hamcrest:2.2"
+test-mockk = "io.mockk:mockk:1.13.5"
test-mockito = "org.mockito:mockito-core:2.23.4"
test-mockitoKotlin = "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
-test-junitJupiterApi = "org.junit.jupiter:junit-jupiter-api:5.7.0"
-test-junitJupiterEngine = "org.junit.jupiter:junit-jupiter-engine:5.7.0"
-test-junitJupiterParams = "org.junit.jupiter:junit-jupiter-params:5.7.0"
+test-junitJupiterApi = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitJupiter" }
+test-junitJupiterEngine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitJupiter" }
+test-junitJupiterParams = { group = "org.junit.jupiter", name = "junit-jupiter-params", version.ref = "junitJupiter" }
[plugins]
dokka = { id = "org.jetbrains.dokka", version = "1.8.10" }
-dcendents = { id = "com.github.dcendents", version = "plugin:2.1" }
bintray = { id = "com.jfrog.bintray", version = "1.8.5" }
pluginPublish = { id = "com.gradle.plugin-publish", version = "0.15.0" }
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts
index f72a74e..be0cf8b 100644
--- a/plugin/build.gradle.kts
+++ b/plugin/build.gradle.kts
@@ -17,7 +17,11 @@ detekt {
// The directories where detekt looks for source files.
// Defaults to `files("src/main/java", "src/test/java", "src/main/kotlin", "src/test/kotlin")`.
- source = files("src/main/java", "src/main/kotlin")
+ source.setFrom("src/main/java", "src/main/kotlin")
+
+ // Specifying a baseline file. All findings stored in this file in subsequent runs of detekt.
+ // A way of suppressing issues before introducing detekt.
+ baseline = file("$projectDir/config/detekt/detekt-baseline.xml")
// Builds the AST in parallel. Rules are always executed in parallel.
// Can lead to speedups in larger projects. `false` by default.
@@ -25,10 +29,7 @@ detekt {
// Define the detekt configuration(s) you want to use.
// Defaults to the default detekt configuration.
- config = files("$projectDir/config/detekt/detekt-config.yml")
-
- // A way of suppressing issues before introducing detekt.
- baseline = file("$projectDir/config/detekt/detekt-baseline.xml")
+ config.setFrom("$projectDir/config/detekt/detekt-config.yml")
// Applies the config files on top of detekt's default config file. `false` by default.
buildUponDefaultConfig = true
@@ -36,9 +37,6 @@ detekt {
// Turns on all the rules. `false` by default.
allRules = false
- // Specifying a baseline file. All findings stored in this file in subsequent runs of detekt.
-// baseline = file("$projectDir/config/baseline.xml")
-
// Disables all default detekt rulesets and will only run detekt with custom rules
// defined in plugins passed in with `detektPlugins` configuration. `false` by default.
disableDefaultRuleSets = false
@@ -90,6 +88,8 @@ dependencies {
implementation(libs.gson)
implementation(libs.okHttp)
compileOnly(libs.androidGradlePlugin)
+ detektPlugins(libs.detektFormating)
+ detektPlugins(libs.detektRules)
testImplementation(libs.test.junitJupiterApi)
testImplementation(libs.test.junitJupiterEngine)
diff --git a/plugin/config/detekt/detekt-config.yml b/plugin/config/detekt/detekt-config.yml
index 2b514fd..c6c04ba 100644
--- a/plugin/config/detekt/detekt-config.yml
+++ b/plugin/config/detekt/detekt-config.yml
@@ -2,30 +2,46 @@ config:
# is automatically ignored when custom-checks.jar is on the classpath
# however other CI checks use the argsfile where our plugin is not applied
# we need to care take of this by explicitly allowing this properties
- excludes: 'custom-checks.*'
+ validation: true
+ excludes: 'custom-detekt-rules'
-custom-checks:
+custom-detekt-rules:
+ RxLazyMethodRule:
+ active: true
+ JupiterTestAnnotationRule:
+ active: true
+ UnintendedCyrillicSymbolsRule:
+ active: true
+ DoesNotExistOutFlakySafelyRule:
+ active: true
+
+libraries:
active: true
- SpekTestDiscovery:
+ ForbiddenPublicDataClass:
+ active: false
+ LibraryEntitiesShouldNotBePublic:
+ active: false
+ LibraryCodeMustSpecifyReturnType:
active: true
- includes: ['**/test/**/*Spec.kt']
+ excludes: [ '**/*.kt' ]
+ includes: [ '**/detekt-api/src/main/**/api/*.kt' ]
comments:
CommentOverPrivateProperty:
- active: true
+ active: false
UndocumentedPublicClass:
active: true
- excludes: ['**/*.kt']
- includes: ['**/detekt-api/src/main/**/api/*.kt']
+ excludes: [ '**/*.kt' ]
+ includes: [ '**/detekt-api/src/main/**/api/*.kt' ]
UndocumentedPublicFunction:
active: true
- excludes: ['**/*.kt']
- includes: ['**/detekt-api/src/main/**/api/*.kt']
+ excludes: [ '**/*.kt' ]
+ includes: [ '**/detekt-api/src/main/**/api/*.kt' ]
complexity:
StringLiteralDuplication:
active: true
- excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt']
+ excludes: [ '**/test/**', '**/*Test.kt' ]
threshold: 5
ignoreAnnotation: true
excludeStringsWithLessThan5Characters: true
@@ -35,21 +51,33 @@ complexity:
threshold: 10
includeStaticDeclarations: false
includePrivateDeclarations: false
- ComplexMethod:
+ excludes: [ '**/*View.*','**/*Binder.*','**/*Module.*','**/*Component.*','**/*Dependencies.*' ]
+ CyclomaticComplexMethod:
active: true
threshold: 15
ignoreSingleWhenExpression: true
LargeClass:
- active: true
- excludes: ['**/test/**', '**/*.Test.kt', '**/*.Spec.kt']
+ active: false
MethodOverloading:
active: true
+ threshold: 10
+ excludes: [ '**/*Component.*' ]
LongParameterList:
active: true
- functionThreshold: 7
- constructorThreshold: 7
+ functionThreshold: 5
+ constructorThreshold: 30
ignoreDefaultParameters: false
ignoreDataClasses: true
+ excludes: [ '**/*Presenter.*', '**/*Analytics.*', '**/*Builder.*', '**/*StructureProvider.*', '**/*Module.*', '**/src/test/**', '**/*Mapper.*', '**/*Dependencies.*' ]
+ ignoreAnnotated: ['Composable']
+ LongMethod:
+ active: false
+ excludes: [ '**/*StructureProvider.*' ]
+ TooManyFunctions:
+ active: false
+ NestedBlockDepth:
+ active: true
+ threshold: 5
coroutines:
active: true
@@ -81,6 +109,10 @@ exceptions:
active: true
ThrowingNewInstanceOfSameException:
active: true
+ SwallowedException:
+ active: false
+ TooGenericExceptionCaught:
+ active: false
formatting:
active: true
@@ -90,17 +122,34 @@ formatting:
active: true
EnumEntryNameCase:
active: true
+ ChainWrapping:
+ active: false
+ CommentSpacing:
+ active: false
+ ImportOrdering:
+ active: false
+ Indentation:
+ active: true
+ FinalNewline:
+ active: false
MaximumLineLength:
active: true
maxLineLength: 120
+ excludes: [ '**/test/**', '**/*Test.kt' ]
MultiLineIfElse:
active: true
+ NoBlankLineBeforeRbrace:
+ active: true
NoEmptyFirstLineInMethodBlock:
active: false
+ NoSemicolons:
+ active: false
NoTrailingSpaces:
active: false
PackageName:
active: true
+ SpacingAroundColon:
+ active: false
SpacingAroundAngleBrackets:
active: true
SpacingAroundDoubleColon:
@@ -108,14 +157,20 @@ formatting:
SpacingAroundUnaryOperator:
active: true
SpacingBetweenDeclarationsWithAnnotations:
- active: true
+ active: false
SpacingBetweenDeclarationsWithComments:
- active: true
+ active: false
+ Wrapping:
+ active: false
+ ArgumentListWrapping:
+ active: false
+ Filename:
+ active: false
naming:
InvalidPackageDeclaration:
active: true
- excludes: ['**/build-logic/**/*.kt', '**/*.kts']
+ excludes: [ '**/build-logic/**/*.kt', '**/*.kts' ]
NoNameShadowing:
active: true
NonBooleanPropertyPrefixedWithIs:
@@ -124,6 +179,12 @@ naming:
active: true
VariableMinLength:
active: true
+ FunctionNaming:
+ ignoreAnnotated: ['Composable']
+
+performance:
+ SpreadOperator:
+ active: false
potential-bugs:
AvoidReferentialEquality:
@@ -140,6 +201,8 @@ potential-bugs:
active: true
ImplicitUnitReturnType:
active: true
+ ImplicitDefaultLocale:
+ active: false
MapGetWithNotNullAssertionOperator:
active: true
UnconditionalJumpStatementInLoop:
@@ -148,17 +211,19 @@ potential-bugs:
active: true
UnsafeCast:
active: true
- excludes: ['**/test/**', '**/*.Test.kt', '**/*.Spec.kt']
+ excludes: [ '**/test/**', '**/*Test.kt', ]
UselessPostfixExpression:
active: true
style:
ClassOrdering:
active: true
+ excludes: [ '**/*Fragment.kt','**/*DialogFragment.kt','**/*Activity.kt' ]
CollapsibleIfStatements:
active: true
DestructuringDeclarationWithTooManyEntries:
active: true
+ maxDestructuringEntries: 5
EqualsOnSignatureLine:
active: true
ExplicitCollectionElementAccessMethod:
@@ -167,22 +232,17 @@ style:
active: true
ForbiddenComment:
active: true
- values:
- - 'TODO:'
- - 'FIXME:'
+ comments:
+ - '^(?i)\b(todo)\b'
- 'STOPSHIP:'
- '@author'
- '@requiresTypeResolution'
- excludes: ['**/detekt-rules-style/**/ForbiddenComment.kt']
+ excludes: [ '**/detekt-rules-style/**/ForbiddenComment.kt' ]
ForbiddenVoid:
active: true
- LibraryCodeMustSpecifyReturnType:
- active: true
- excludes: ['**/*.kt']
- includes: ['**/detekt-api/src/main/**/api/*.kt']
MagicNumber:
- excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt']
- ignoreNumbers: ['-1', '0', '1', '2', '100', '100.0', '1000']
+ excludes: [ '**/test/**', '**/*Test.kt', '**/*RealmMigrationProvider*' ]
+ ignoreNumbers: [ '-1', '0', '1', '2','3','4','5','6','7','8','9', '100', '100.0', '1000' ]
ignorePropertyDeclaration: true
ignoreAnnotation: true
ignoreEnums: true
@@ -193,11 +253,12 @@ style:
ignoreNamedArgument: true
ignoreRanges: false
ignoreExtensionFunctions: true
+ ignoreAnnotated: ['Composable']
MandatoryBracesLoops:
active: true
MaxLineLength:
active: true
- excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt']
+ excludes: [ '**/test/**', '**/*Test.kt' ]
excludeCommentStatements: true
NestedClassesVisibility:
active: true
@@ -218,9 +279,11 @@ style:
excludeGuardClauses: true
SpacingBetweenPackageAndImports:
active: true
+ SerialVersionUIDInSerializableClass:
+ active: false
ThrowsCount:
- active: true
max: 3
+ excludeGuardClauses: false
UnderscoresInNumericLiterals:
active: false
UnnecessaryAnnotationUseSiteTarget:
@@ -236,6 +299,15 @@ style:
UnusedPrivateMember:
active: true
allowedNames: '(_|ignored|expected)'
+ excludes: [ '**/*Request.kt' ]
+ ignoreAnnotated:
+ - 'Preview'
+ UnusedPrivateProperty:
+ active: true
+ allowedNames: '(_|ignored|expected)'
+ excludes: [ '**/*Request.kt' ]
+ ignoreAnnotated:
+ - 'Preview'
UseCheckOrError:
active: false
UseDataClass:
@@ -253,6 +325,13 @@ style:
UseRequireNotNull:
active: true
UtilityClassWithPublicConstructor:
- active: false
+ active: true
+ UnnecessaryAbstractClass:
+ active: true
WildcardImport:
active: true
+
+empty-blocks:
+ EmptyFunctionBlock:
+ active: true
+ ignoreOverridden: true
\ No newline at end of file
diff --git a/plugin/gradle.properties b/plugin/gradle.properties
new file mode 100644
index 0000000..b2331cb
--- /dev/null
+++ b/plugin/gradle.properties
@@ -0,0 +1,47 @@
+org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
+org.gradle.workers.max=2
+kotlin.code.style=official
+org.gradle.parallel=false
+
+android.useAndroidX=true
+android.enableJetifier=true
+
+####################################################################################################
+
+GROUP_ID=ru.cian.rustore-plugin
+VERSION_NAME=0.3.2
+IS_SNAPSHOT=true
+
+POM_ARTIFACT_ID=rustore-publish-gradle-plugin
+POM_NAME=Rustore Publish Gradle Plugin
+POM_PACKAGING=jar
+
+POM_DESCRIPTION=A Gradle Plugin for publishing release built to Rustore
+POM_INCEPTION_YEAR=2020
+
+POM_URL=https://github.com/cianru/rustore-publish-gradle-plugin
+POM_SCM_URL=https://github.com/cianru/rustore-publish-gradle-plugin
+POM_SCM_GITHUB_URL=https://github.com/cianru/rustore-publish-gradle-plugin.git
+POM_SCM_CONNECTION=scm:git:git://github.com/cianru/rustore-publish-gradle-plugin.git
+POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/cianru/rustore-publish-gradle-plugin.git
+
+POM_LICENSE_NAME=The Apache Software License, Version 2.0
+POM_LICENSE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
+POM_LICENSE_DIST=repo
+
+POM_DEVELOPER_ID=cianru
+POM_DEVELOPER_NAME=CIAN, Inc.
+POM_DEVELOPER_EMAIL=opensource@cian.ru
+POM_DEVELOPER_CITE=www.cian.ru
+
+BINTRAY_REPO=ru.cian
+BINTRAY_PKG=rustore-publish-gradle-plugin
+
+GRADLE_PORTAL_URL=https://github.com/cianru/rustore-publish-gradle-plugin
+GRADLE_PORTAL_SCM_URL=https://github.com/cianru/rustore-publish-gradle-plugin.git
+GRADLE_PORTAL_ARTIFACT_ID=ru.cian.rustore-publish-gradle-plugin
+GRADLE_PORTAL_NAME=Rustore Publish Gradle Plugin
+GRADLE_PORTAL_DESCRIPTION=A Gradle Plugin for publishing release built to Rustore
+GRADLE_PORTAL_IMPLEMENTATION_CLASS=ru.cian.rustore.publish.RustorePublishPlugin
+
+####################################################################################################
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishConfig.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishConfig.kt
index b36b9a9..209f5de 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishConfig.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishConfig.kt
@@ -6,6 +6,7 @@ internal data class InputPluginConfig(
val credentials: Credentials,
val deployType: DeployType,
val artifactFormat: BuildFormat,
+ val mobileServicesType: MobileServicesType,
val artifactFile: File,
val releaseTime: String?,
val releasePhase: ReleasePhaseConfig?,
@@ -27,6 +28,7 @@ internal data class InputPluginCliParam(
val credentialsPath: String? = null,
val companyId: String? = null,
val clientSecret: String? = null,
+ val mobileServicesType: MobileServicesType? = null,
val buildFormat: BuildFormat? = null,
val buildFile: String? = null,
val releaseTime: String? = null,
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishExtension.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishExtension.kt
index 227f7fa..fdeacdc 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishExtension.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishExtension.kt
@@ -28,6 +28,7 @@ class RustorePublishExtensionConfig(
*/
var credentialsPath: String? = null
var deployType = DeployType.PUBLISH
+ var mobileServicesType: MobileServicesType = MobileServicesType.UNKNOWN
var buildFormat: BuildFormat = BuildFormat.APK
var buildFile: String? = null
var releaseTime: String? = null
@@ -35,8 +36,8 @@ class RustorePublishExtensionConfig(
var releaseNotes: List? = null
init {
- if (name.isBlank()) {
- throw IllegalArgumentException("Name must not be blank nor empty")
+ require(name.isNotBlank()) {
+ "Name must not be blank nor empty"
}
}
@@ -51,6 +52,7 @@ class RustorePublishExtensionConfig(
"name='$name', " +
"credentialsPath='$credentialsPath', " +
"deployType='$deployType', " +
+ "mobileServicesType='$mobileServicesType', " +
"buildFormat='$buildFormat', " +
"buildFile='$buildFile', " +
"releaseTime='$releaseTime', " +
@@ -91,9 +93,9 @@ open class ReleaseNote {
override fun toString(): String {
return "ReleaseNote(" +
- "lang='$lang', " +
- "filePath='$filePath'" +
- ")"
+ "lang='$lang', " +
+ "filePath='$filePath'" +
+ ")"
}
}
@@ -102,6 +104,11 @@ enum class BuildFormat(val fileExtension: String) {
AAB("aab"),
}
+enum class MobileServicesType(val value: String) {
+ HMS("HMS"),
+ UNKNOWN("Unknown"),
+}
+
enum class DeployType {
/**
* Deploy without draft saving and submit on users;
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishPlugin.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishPlugin.kt
index 5a66bbf..ffd3d41 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishPlugin.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishPlugin.kt
@@ -32,7 +32,7 @@ class RustorePublishPlugin : Plugin {
}
}
- @Suppress("DefaultLocale")
+ @Suppress("DefaultLocale", "UnusedPrivateProperty")
private fun createTask(
project: Project,
variant: ApplicationVariant,
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishTask.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishTask.kt
index 53a3df9..982bfc7 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishTask.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/RustorePublishTask.kt
@@ -74,6 +74,16 @@ open class RustorePublishTask
)
var buildFormat: BuildFormat? = null
+ @Suppress("MaxLineLength")
+ @get:Internal
+ @set:Option(
+ option = "mobileServicesType",
+ description = "Type of mobile services used in application. Available values: [\"Unknown\", \"HMS\"]. " +
+ "For more details see param `servicesType` in documentation " +
+ "https://www.rustore.ru/help/work-with-rustore-api/api-upload-publication-app/apk-file-upload/file-upload-apk/"
+ )
+ var mobileServicesType: MobileServicesType? = null
+
@get:Internal
@set:Option(
option = "buildFile",
@@ -131,6 +141,7 @@ open class RustorePublishTask
credentialsPath = credentialsPath,
companyId = companyId,
clientSecret = clientSecret,
+ mobileServicesType = mobileServicesType,
buildFormat = buildFormat,
buildFile = buildFile,
releaseTime = releaseTime,
@@ -156,8 +167,9 @@ open class RustorePublishTask
logger.v("Found build file: `${config.artifactFile.name}`")
logger.v("2/6. Create signature")
- val timestamp = ZonedDateTime.now().format(DateTimeFormatter.ofPattern(DATETIME_FORMAT_ISO8601))
- val salt = "${config.credentials.companyId}${timestamp}"
+ val datetimeFormatPattern = DateTimeFormatter.ofPattern(DATETIME_FORMAT_ISO8601)
+ val timestamp = ZonedDateTime.now().format(datetimeFormatPattern)
+ val salt = "${config.credentials.companyId}$timestamp"
val signatureTools: SignatureTools = if (apiStub != true) SignatureToolsImpl() else MockSignatureTools()
val signature = signatureTools.signData(salt, config.credentials.clientSecret)
@@ -179,6 +191,7 @@ open class RustorePublishTask
rustoreService.uploadBuildFile(
token = token,
applicationId = config.applicationId,
+ mobileServicesType = config.mobileServicesType.value,
versionId = appVersionId,
buildFile = config.artifactFile
)
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/HttpClientHelper.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/HttpClientHelper.kt
index 73cfd7f..b58df20 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/HttpClientHelper.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/HttpClientHelper.kt
@@ -41,12 +41,6 @@ internal class HttpClientHelper constructor(
.build()
return client.newCall(request).execute().use { httpResponse ->
- val statusCode = httpResponse.code
-
-// if (!httpResponse.isSuccessful) { // TODO handle and remove;
-// throw IllegalStateException("Request failed. statusCode=$statusCode, httpResponse=$httpResponse")
-// }
-
gson.fromJson(httpResponse.body?.charStream(), T::class.java)
?: throw IllegalStateException("http request result must not be null")
}
@@ -59,6 +53,6 @@ internal class HttpClientHelper constructor(
companion object {
val MEDIA_TYPE_JSON = "application/json;charset=utf-8".toMediaType()
val MEDIA_TYPE_AAB = "application/octet-stream".toMediaType()
- private val REQUEST_TIMEOUT = 60L
+ private const val REQUEST_TIMEOUT = 60L
}
}
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/MockRustoreService.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/MockRustoreService.kt
index bde1bf7..18c16cf 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/MockRustoreService.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/MockRustoreService.kt
@@ -2,8 +2,6 @@ package ru.cian.rustore.publish.service
import java.io.File
-private const val REQUEST_RETRIES = 5
-
@SuppressWarnings("StringLiteralDuplication", "TooManyFunctions")
internal class MockRustoreService : RustoreService {
@@ -15,13 +13,14 @@ internal class MockRustoreService : RustoreService {
token: String,
applicationId: String,
whatsNew: String,
- ): Int {
+ ): Int {
return -1
}
override fun uploadBuildFile(
token: String,
applicationId: String,
+ mobileServicesType: String,
versionId: Int,
buildFile: File
) {
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreService.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreService.kt
index 6d18ddf..9290212 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreService.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreService.kt
@@ -20,9 +20,11 @@ internal interface RustoreService {
whatsNew: String,
): Int
+ @Suppress("LongParameterList")
fun uploadBuildFile(
token: String,
applicationId: String,
+ mobileServicesType: String,
versionId: Int,
buildFile: File,
)
@@ -33,5 +35,4 @@ internal interface RustoreService {
versionId: Int,
priorityUpdate: Int,
): Boolean
-
}
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreServiceImpl.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreServiceImpl.kt
index 93157e0..4ea1899 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreServiceImpl.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/service/RustoreServiceImpl.kt
@@ -121,6 +121,7 @@ internal class RustoreServiceImpl constructor(
override fun uploadBuildFile(
token: String,
applicationId: String,
+ mobileServicesType: String,
versionId: Int,
buildFile: File
) {
@@ -129,7 +130,7 @@ internal class RustoreServiceImpl constructor(
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", buildFile.name, fileBody)
- .addFormDataPart("servicesType", "Unknown")
+ .addFormDataPart("servicesType", mobileServicesType)
.addFormDataPart("isMainApk", "true")
.build()
@@ -138,6 +139,16 @@ internal class RustoreServiceImpl constructor(
"Public-Token" to token,
)
+ logger.i("""
+ curl --location --request POST \
+ --header 'Content-Type: application/json' \
+ --header 'Public-Token: $token' \
+ --form servicesType=$mobileServicesType \
+ --form isMainApk=true \
+ --form file='@${buildFile.absolutePath}' \
+ $DOMAIN_URL/public/v1/application/$applicationId/version/$versionId/apk
+ """.trimIndent())
+
val response = httpClient.post(
url = "$DOMAIN_URL/public/v1/application/$applicationId/version/$versionId/apk",
body = requestBody,
@@ -146,7 +157,7 @@ internal class RustoreServiceImpl constructor(
logger.v("response=$response")
- check (response.code == "OK") {
+ check(response.code == "OK") {
"Build file uploading is failed! " +
"Reason code: ${response.code}, " +
"message: ${response.message}"
@@ -166,7 +177,8 @@ internal class RustoreServiceImpl constructor(
""".trimIndent())
val response = httpClient.post(
- url = "$DOMAIN_URL/public/v1/application/$applicationId/version/$versionId/commit?priorityUpdate=$priorityUpdate",
+ url = "$DOMAIN_URL/public/v1/application/$applicationId/version/$versionId/commit" +
+ "?priorityUpdate=$priorityUpdate",
body = "".toRequestBody(),
headers = mapOf(
"Content-Type" to "application/json",
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/BuildFileProvider.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/BuildFileProvider.kt
index 2b2b549..314b126 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/BuildFileProvider.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/BuildFileProvider.kt
@@ -5,7 +5,7 @@ import com.android.build.api.variant.ApplicationVariant
import ru.cian.rustore.publish.BuildFormat
import java.io.File
-internal class BuildFileProvider constructor(
+internal class BuildFileProvider(
private val variant: ApplicationVariant,
private val logger: Logger,
) {
@@ -17,8 +17,8 @@ internal class BuildFileProvider constructor(
}
}
- // TODO(a.mirko): Remove after https://github.com/gradle/gradle/issues/16777
- // TODO(a.mirko): Remove after https://github.com/gradle/gradle/issues/16775
+ // FIXME(a.mirko): Remove after https://github.com/gradle/gradle/issues/16777
+ // FIXME(a.mirko): Remove after https://github.com/gradle/gradle/issues/16775
private fun getFinalApkArtifactCompat(variant: ApplicationVariant): List {
val apkDirectory = variant.artifacts.get(SingleArtifact.APK).get()
logger.v("Build File Directory: $apkDirectory")
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ConfigProvider.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ConfigProvider.kt
index f5a5632..811f081 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ConfigProvider.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ConfigProvider.kt
@@ -20,6 +20,7 @@ internal class ConfigProvider(
fun getConfig(): InputPluginConfig {
+ val mobileServicesType = cli.mobileServicesType ?: extension.mobileServicesType
val deployType = cli.deployType ?: extension.deployType
val artifactFormat = cli.buildFormat ?: extension.buildFormat
val customBuildFilePath: String? = cli.buildFile ?: extension.buildFile
@@ -43,6 +44,7 @@ internal class ConfigProvider(
return InputPluginConfig(
credentials = credentialsConfig,
deployType = deployType,
+ mobileServicesType = mobileServicesType,
artifactFormat = actualArtifactFormat,
artifactFile = artifactFile,
releaseTime = releaseTime,
@@ -52,7 +54,7 @@ internal class ConfigProvider(
)
}
- fun getBuildFile(
+ private fun getBuildFile(
customBuildFilePath: String?,
artifactFormat: BuildFormat
): File {
@@ -66,21 +68,21 @@ internal class ConfigProvider(
if (artifactFile == null || !artifactFile.exists()) {
throw FileNotFoundException(
"$artifactFile (No such file or directory). Application build file is not found. " +
- "Please run `assemble` or `bundle` task to build the application file before current task."
+ "Please run `assemble` or `bundle` task to build the application file before current task."
)
}
if (artifactFormat.fileExtension != artifactFile.extension) {
throw IllegalArgumentException(
"Build file ${artifactFile.absolutePath} has wrong file extension " +
- "that doesn't match with announced buildFormat($artifactFormat) plugin extension param."
+ "that doesn't match with announced buildFormat($artifactFormat) plugin extension param."
)
}
return artifactFile
}
@Suppress("ThrowsCount")
- fun getCredentialsConfig(): Credentials {
+ private fun getCredentialsConfig(): Credentials {
val credentialsFilePath = cli.credentialsPath ?: extension.credentialsPath
val companyIdPriority: String? = cli.companyId
val clientSecretPriority: String? = cli.clientSecret
@@ -88,33 +90,35 @@ internal class ConfigProvider(
if (credentialsFilePath.isNullOrBlank()) {
throw FileNotFoundException(
"$extension (File path for credentials is null or empty. " +
- "See the `credentialsPath` param description."
+ "See the `credentialsPath` param description."
)
}
val credentialsFile = File(credentialsFilePath)
if (!credentialsFile.exists()) {
throw FileNotFoundException(
"$extension (File (${credentialsFile.absolutePath}) " +
- "with 'company_id' and 'client_secret' for access to Rustore Publish API is not found)"
+ "with 'company_id' and 'client_secret' for access to Rustore Publish API is not found)"
)
}
CredentialHelper.getCredentials(credentialsFile)
}
- val companyId = companyIdPriority ?: credentials.value.companyId.nullIfBlank()
- ?: throw IllegalArgumentException(
- "(Rustore credential `companyId` param is null or empty). " +
+ val companyId = companyIdPriority
+ ?: credentials.value.companyId.nullIfBlank()
+ ?: throw IllegalArgumentException(
+ "(Rustore credential `companyId` param is null or empty). " +
"Please check your credentials file content or as single parameter."
- )
- val clientSecret = clientSecretPriority ?: credentials.value.clientSecret.nullIfBlank()
- ?: throw IllegalArgumentException(
- "(Rustore credential `clientSecret` param is null or empty). " +
+ )
+ val clientSecret = clientSecretPriority
+ ?: credentials.value.clientSecret.nullIfBlank()
+ ?: throw IllegalArgumentException(
+ "(Rustore credential `clientSecret` param is null or empty). " +
"Please check your credentials file content or as single parameter."
- )
+ )
return Credentials(companyId, clientSecret)
}
@Suppress("ThrowsCount")
- fun getReleasePhaseConfig(): ReleasePhaseConfig? {
+ private fun getReleasePhaseConfig(): ReleasePhaseConfig? {
val releasePhasePercent = cli.releasePhasePercent?.toDouble() ?: extension.releasePhase?.percent
if (releasePhasePercent != null) {
@@ -149,29 +153,20 @@ internal class ConfigProvider(
return releaseNotePairs?.map {
val lang = it.first
- val filePath = it.second
-
- if (lang.isBlank()) {
- throw IllegalArgumentException(
- "'lang' param must not be empty."
- )
+ require(lang.isNotBlank()) {
+ "'lang' param must not be empty."
}
+ val filePath = it.second
val file = releaseNotesFileProvider.getFile(filePath)
-
- if (!file.exists()) {
- throw IllegalArgumentException(
- "File '$filePath' with Release Notes for '$lang' language is not exist."
- )
+ require(file.exists()) {
+ "File '$filePath' with Release Notes for '$lang' language is not exist."
}
val newFeatures = file.readText(Charsets.UTF_8)
-
- if (newFeatures.length > RELEASE_NOTES_MAX_LENGTH) {
- throw IllegalArgumentException(
- "Release notes from '$filePath' for '$lang' language " +
- "must be less or equals to $RELEASE_NOTES_MAX_LENGTH sign."
- )
+ require(newFeatures.length <= RELEASE_NOTES_MAX_LENGTH) {
+ "Release notes from '$filePath' for '$lang' language " +
+ "must be less or equals to $RELEASE_NOTES_MAX_LENGTH sign."
}
ReleaseNotesConfig(
diff --git a/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ServerPollingExecutor.kt b/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ServerPollingExecutor.kt
index 0a5f7c7..e33e563 100644
--- a/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ServerPollingExecutor.kt
+++ b/plugin/src/main/kotlin/ru/cian/rustore/publish/utils/ServerPollingExecutor.kt
@@ -4,7 +4,7 @@ import java.util.concurrent.TimeoutException
internal class ServerPollingExecutor {
- @Suppress("TooGenericExceptionCaught")
+ @Suppress("TooGenericExceptionCaught", "LongParameterList")
fun run(
periodTimeInMs: Long,
timeoutInMs: Long,
diff --git a/plugin/src/test/kotlin/ru/cian/rustore/publish/utils/ConfigProviderTest.kt b/plugin/src/test/kotlin/ru/cian/rustore/publish/utils/ConfigProviderTest.kt
index bb179ba..5103803 100644
--- a/plugin/src/test/kotlin/ru/cian/rustore/publish/utils/ConfigProviderTest.kt
+++ b/plugin/src/test/kotlin/ru/cian/rustore/publish/utils/ConfigProviderTest.kt
@@ -13,6 +13,17 @@ import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
+import ru.cian.rustore.publish.BuildFormat
+import ru.cian.rustore.publish.Credentials
+import ru.cian.rustore.publish.DeployType
+import ru.cian.rustore.publish.InputPluginCliParam
+import ru.cian.rustore.publish.InputPluginConfig
+import ru.cian.rustore.publish.MobileServicesType
+import ru.cian.rustore.publish.ReleaseNote
+import ru.cian.rustore.publish.ReleaseNotesConfig
+import ru.cian.rustore.publish.ReleasePhaseConfig
+import ru.cian.rustore.publish.ReleasePhaseExtension
+import ru.cian.rustore.publish.RustorePublishExtensionConfig
import ru.cian.rustore.publish.models.Credential
import java.io.File
@@ -38,14 +49,14 @@ private const val APP_BASIC_INFO_FILE_SECOND_PATH = "$BUILD_DIRECTORY_PATH/app_i
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class ConfigProviderTest {
- private val buildFileProvider = mockk()
private val project = mockk()
+ private val buildFileProvider = mockk()
private val releaseNotesFileProvider = mockk()
-
- private val emptyCliConfig = ru.cian.rustore.publish.InputPluginCliParam()
+ private val applicationId = "applicationId_1234567890"
+ private val emptyCliConfig = InputPluginCliParam()
private fun extensionConfigInstance() = run {
- ru.cian.rustore.publish.RustorePublishExtensionConfig("any", project).apply {
+ RustorePublishExtensionConfig("any", project).apply {
credentialsPath = CREDENTIALS_FILE_PATH
}
}
@@ -96,15 +107,15 @@ internal class ConfigProviderTest {
@BeforeEach
fun beforeEach() {
- every { buildFileProvider.getBuildFile(ru.cian.rustore.publish.BuildFormat.APK) } returns File(ARTIFACT_APK_FILE_PATH)
- every { buildFileProvider.getBuildFile(ru.cian.rustore.publish.BuildFormat.AAB) } returns File(ARTIFACT_AAB_FILE_PATH)
+ every { buildFileProvider.getBuildFile(BuildFormat.APK) } returns File(ARTIFACT_APK_FILE_PATH)
+ every { buildFileProvider.getBuildFile(BuildFormat.AAB) } returns File(ARTIFACT_AAB_FILE_PATH)
}
@Test
fun `get error to build config for wrong artifact file`() = mockkObject(CredentialHelper) {
- val cliConfig = ru.cian.rustore.publish.InputPluginCliParam(
- buildFormat = ru.cian.rustore.publish.BuildFormat.APK,
+ val cliConfig = InputPluginCliParam(
+ buildFormat = BuildFormat.APK,
buildFile = WRONG_ARTIFACT_FILE_PATH
)
val configProvider = ConfigProvider(
@@ -112,6 +123,7 @@ internal class ConfigProviderTest {
cli = cliConfig,
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
assertThat { configProvider.getConfig() }.hasException(IllegalArgumentException::class)
@@ -120,14 +132,16 @@ internal class ConfigProviderTest {
@Test
fun `correct config for default params`() = mockkObject(CredentialHelper) {
- val expectedConfig = ru.cian.rustore.publish.InputPluginConfig(
- credentials = ru.cian.rustore.publish.Credentials("id", "secret"),
- deployType = ru.cian.rustore.publish.DeployType.PUBLISH,
- artifactFormat = ru.cian.rustore.publish.BuildFormat.APK,
+ val expectedConfig = InputPluginConfig(
+ credentials = Credentials("id", "secret"),
+ deployType = DeployType.PUBLISH,
+ artifactFormat = BuildFormat.APK,
+ mobileServicesType = MobileServicesType.UNKNOWN,
artifactFile = File(ARTIFACT_APK_FILE_PATH),
releaseTime = null,
releasePhase = null,
releaseNotes = null,
+ applicationId = applicationId,
)
every {
@@ -142,17 +156,19 @@ internal class ConfigProviderTest {
cli = emptyCliConfig,
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
expectedConfig,
ConfigProvider(
extension = extensionConfigInstance(),
- cli = ru.cian.rustore.publish.InputPluginCliParam(
+ cli = InputPluginCliParam(
credentialsPath = CREDENTIALS_FILE_PATH
),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.forAll { expectedValue, actualValue ->
@@ -163,34 +179,36 @@ internal class ConfigProviderTest {
@Test
fun `correct config with overriding common values at cli params`() {
- val expectedConfig = ru.cian.rustore.publish.InputPluginConfig(
- credentials = ru.cian.rustore.publish.Credentials("id123", "secret123"),
- deployType = ru.cian.rustore.publish.DeployType.DRAFT,
- artifactFormat = ru.cian.rustore.publish.BuildFormat.AAB,
+ val expectedConfig = InputPluginConfig(
+ credentials = Credentials("id123", "secret123"),
+ deployType = DeployType.DRAFT,
+ artifactFormat = BuildFormat.AAB,
artifactFile = File(ARTIFACT_AAB_FILE_SECOND_PATH),
+ mobileServicesType = MobileServicesType.UNKNOWN,
releaseTime = "2019-10-18T21:00:00+0300",
- releasePhase = ru.cian.rustore.publish.ReleasePhaseConfig(
+ releasePhase = ReleasePhaseConfig(
percent = 10.05
),
releaseNotes = null,
+ applicationId = applicationId,
)
val inputExtensionConfig = extensionConfigInstance().apply {
credentialsPath = CREDENTIALS_FILE_PATH
- deployType = ru.cian.rustore.publish.DeployType.PUBLISH
- buildFormat = ru.cian.rustore.publish.BuildFormat.APK
+ deployType = DeployType.PUBLISH
+ buildFormat = BuildFormat.APK
buildFile = ARTIFACT_APK_FILE_PATH
releaseTime = "2000-10-18T21:00:00+0300"
- releasePhase = ru.cian.rustore.publish.ReleasePhaseExtension().apply {
+ releasePhase = ReleasePhaseExtension().apply {
percent = 99.7
}
}
- val inputCliConfig = ru.cian.rustore.publish.InputPluginCliParam(
- deployType = ru.cian.rustore.publish.DeployType.DRAFT,
+ val inputCliConfig = InputPluginCliParam(
+ deployType = DeployType.DRAFT,
credentialsPath = CREDENTIALS_FILE_SECOND_PATH,
companyId = "id123",
clientSecret = "secret123",
- buildFormat = ru.cian.rustore.publish.BuildFormat.AAB,
+ buildFormat = BuildFormat.AAB,
buildFile = ARTIFACT_AAB_FILE_SECOND_PATH,
releaseTime = "2019-10-18T21:00:00+0300",
releasePhasePercent = "10.05",
@@ -200,6 +218,7 @@ internal class ConfigProviderTest {
cli = inputCliConfig,
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
val actualValue = configProvider.getConfig()
@@ -211,72 +230,79 @@ internal class ConfigProviderTest {
@Test
fun `correct config with overriding of publish param`() {
- val expectedConfig = ru.cian.rustore.publish.InputPluginConfig(
- credentials = ru.cian.rustore.publish.Credentials("id", "secret"),
- deployType = ru.cian.rustore.publish.DeployType.PUBLISH,
- artifactFormat = ru.cian.rustore.publish.BuildFormat.APK,
+ val expectedConfig = InputPluginConfig(
+ credentials = Credentials("id", "secret"),
+ deployType = DeployType.PUBLISH,
+ artifactFormat = BuildFormat.APK,
+ mobileServicesType = MobileServicesType.UNKNOWN,
artifactFile = File(ARTIFACT_APK_FILE_PATH),
releaseTime = null,
releasePhase = null,
releaseNotes = null,
+ applicationId = applicationId,
)
tableOf("expectedValue", "actualValue")
.row(
- expectedConfig.copy(deployType = ru.cian.rustore.publish.DeployType.PUBLISH),
+ expectedConfig.copy(deployType = DeployType.PUBLISH),
ConfigProvider(
extension = extensionConfigInstance(),
- cli = ru.cian.rustore.publish.InputPluginCliParam(),
+ cli = InputPluginCliParam(),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
- expectedConfig.copy(deployType = ru.cian.rustore.publish.DeployType.DRAFT),
+ expectedConfig.copy(deployType = DeployType.DRAFT),
ConfigProvider(
extension = extensionConfigInstance().apply {
- deployType = ru.cian.rustore.publish.DeployType.DRAFT
+ deployType = DeployType.DRAFT
},
- cli = ru.cian.rustore.publish.InputPluginCliParam(),
+ cli = InputPluginCliParam(),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
- expectedConfig.copy(deployType = ru.cian.rustore.publish.DeployType.UPLOAD_ONLY),
+ expectedConfig.copy(deployType = DeployType.UPLOAD_ONLY),
ConfigProvider(
extension = extensionConfigInstance().apply {
- deployType = ru.cian.rustore.publish.DeployType.UPLOAD_ONLY
+ deployType = DeployType.UPLOAD_ONLY
},
- cli = ru.cian.rustore.publish.InputPluginCliParam(),
+ cli = InputPluginCliParam(),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
- expectedConfig.copy(deployType = ru.cian.rustore.publish.DeployType.DRAFT),
+ expectedConfig.copy(deployType = DeployType.DRAFT),
ConfigProvider(
extension = extensionConfigInstance().apply {
- deployType = ru.cian.rustore.publish.DeployType.DRAFT
+ deployType = DeployType.DRAFT
},
- cli = ru.cian.rustore.publish.InputPluginCliParam(
+ cli = InputPluginCliParam(
deployType = null
),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
- expectedConfig.copy(deployType = ru.cian.rustore.publish.DeployType.UPLOAD_ONLY),
+ expectedConfig.copy(deployType = DeployType.UPLOAD_ONLY),
ConfigProvider(
extension = extensionConfigInstance().apply {
- deployType = ru.cian.rustore.publish.DeployType.DRAFT
+ deployType = DeployType.DRAFT
},
- cli = ru.cian.rustore.publish.InputPluginCliParam(
- deployType = ru.cian.rustore.publish.DeployType.UPLOAD_ONLY
+ cli = InputPluginCliParam(
+ deployType = DeployType.UPLOAD_ONLY
),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.forAll { expectedValue, actualValue ->
@@ -287,14 +313,16 @@ internal class ConfigProviderTest {
@Suppress("LongMethod")
@Test
fun `correct config with overriding release notes`() {
- val expectedConfig = ru.cian.rustore.publish.InputPluginConfig(
- credentials = ru.cian.rustore.publish.Credentials("id", "secret"),
- deployType = ru.cian.rustore.publish.DeployType.PUBLISH,
- artifactFormat = ru.cian.rustore.publish.BuildFormat.APK,
+ val expectedConfig = InputPluginConfig(
+ credentials = Credentials("id", "secret"),
+ deployType = DeployType.PUBLISH,
+ artifactFormat = BuildFormat.APK,
+ mobileServicesType = MobileServicesType.UNKNOWN,
artifactFile = File(ARTIFACT_APK_FILE_PATH),
releaseTime = null,
releasePhase = null,
releaseNotes = null,
+ applicationId = applicationId,
)
val langRu = "lang_ru_RU"
val releaseNotesRu = "Some release notes for ru_RU"
@@ -318,7 +346,7 @@ internal class ConfigProviderTest {
tableOf("expectedValue", "actualValue")
.row(
expectedConfig.copy(releaseNotes = listOf(
- ru.cian.rustore.publish.ReleaseNotesConfig(
+ ReleaseNotesConfig(
lang = langRu,
newFeatures = releaseNotesRu
)
@@ -326,36 +354,38 @@ internal class ConfigProviderTest {
ConfigProvider(
extension = extensionConfigInstance().apply {
releaseNotes = listOf(
- ru.cian.rustore.publish.ReleaseNote(
+ ReleaseNote(
lang = langRu,
filePath = releaseNotesRuFilePath
)
)
},
- cli = ru.cian.rustore.publish.InputPluginCliParam(),
+ cli = InputPluginCliParam(),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
expectedConfig.copy(releaseNotes = listOf(
- ru.cian.rustore.publish.ReleaseNotesConfig(
+ ReleaseNotesConfig(
lang = langRu,
newFeatures = releaseNotesRu
)
)),
ConfigProvider(
extension = extensionConfigInstance(),
- cli = ru.cian.rustore.publish.InputPluginCliParam(
+ cli = InputPluginCliParam(
releaseNotes = "$langRu:$releaseNotesRuFilePath"
),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.row(
expectedConfig.copy(releaseNotes = listOf(
- ru.cian.rustore.publish.ReleaseNotesConfig(
+ ReleaseNotesConfig(
lang = langEn,
newFeatures = releaseNotesEn
)
@@ -363,17 +393,18 @@ internal class ConfigProviderTest {
ConfigProvider(
extension = extensionConfigInstance().apply {
releaseNotes = listOf(
- ru.cian.rustore.publish.ReleaseNote(
+ ReleaseNote(
lang = langRu,
filePath = releaseNotesRuFilePath
)
)
},
- cli = ru.cian.rustore.publish.InputPluginCliParam(
+ cli = InputPluginCliParam(
releaseNotes = "$langEn:$releaseNotesEnFilePath"
),
buildFileProvider = buildFileProvider,
releaseNotesFileProvider = releaseNotesFileProvider,
+ applicationId = applicationId,
)
)
.forAll { expectedValue, actualValue ->
diff --git a/sample-groovy/build.gradle b/sample-groovy/build.gradle
index abb2172..00c2ecc 100644
--- a/sample-groovy/build.gradle
+++ b/sample-groovy/build.gradle
@@ -6,7 +6,7 @@ buildscript {
}
dependencies {
- classpath "ru.cian.rustore-plugin:plugin:" + libs.versions.sampleRustorePlugin.get()
+ classpath "ru.cian.rustore-plugin:rustore-publish-gradle-plugin:" + libs.versions.sampleRustorePlugin.get()
}
}
diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts
index 3ec204a..6256cdd 100644
--- a/sample-kotlin/build.gradle.kts
+++ b/sample-kotlin/build.gradle.kts
@@ -8,6 +8,7 @@ rustorePublish {
instances {
create("release") {
credentialsPath = "$projectDir/rustore-credentials.json"
+ mobileServicesType = ru.cian.rustore.publish.MobileServicesType.HMS
releaseNotes = listOf(
ru.cian.rustore.publish.ReleaseNote(
lang = "ru-RU",
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d05910c..2b013f5 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -8,16 +8,20 @@ include(
pluginManagement {
- val rustorePublish = "0.3.1-SNAPSHOT"
+ val rustorePublish = "0.3.2-SNAPSHOT"
resolutionStrategy {
eachPlugin {
if(requested.id.namespace == "ru.cian") {
- useModule("ru.cian.rustore-plugin:plugin:${rustorePublish}")
+ useModule("ru.cian.rustore-plugin:rustore-publish-gradle-plugin:${rustorePublish}")
}
}
}
+ plugins {
+ id("ru.cian.rustore-publish-gradle-plugin") version rustorePublish apply false
+ }
+
repositories {
mavenLocal()
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }