diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 700b25d..819a3b2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,8 +14,6 @@ on: jobs: sdk-build: runs-on: ubuntu-latest - if: > - github.event_name != 'workflow_dispatch' env: GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4g -XX:MaxMetaspaceSize=2g -Dkotlin.daemon.jvm.options=-Xmx1536m" steps: @@ -30,6 +28,19 @@ jobs: run: ./scripts/verify-publications.bash sdk - name: Check sdk-mock publications run: ./scripts/verify-publications.bash sdkMock + - run: ./gradlew sdk:generateMetaDataJson + - run: | + ls -R ~/.m2/repository + + mkdir -p tmp/artifacts + cp -r ~/.m2/repository/com/deploygate/* tmp/artifacts/ + cp sdk/build/generated-sdk-metadata/sdk-meta-data-* tmp/artifacts/ + - uses: actions/upload-artifact@v4 + with: + name: artifacts + path: tmp/artifacts + retention-days: 3 + if-no-files-found: error build-and-upload: runs-on: ubuntu-latest diff --git a/plugins/library/build.gradle.kts b/plugins/library/build.gradle.kts index 3e6d861..0499f58 100644 --- a/plugins/library/build.gradle.kts +++ b/plugins/library/build.gradle.kts @@ -5,6 +5,7 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22") implementation("com.android.tools.build:gradle:7.4.2") + implementation("com.squareup.moshi:moshi-kotlin:1.15.0") } gradlePlugin { @@ -13,5 +14,9 @@ gradlePlugin { id = "com.deploygate.plugins.sdk" implementationClass = "com.deploygate.plugins.SdkPlugin" } + create("sdk-mock") { + id = "com.deploygate.plugins.sdk-mock" + implementationClass = "com.deploygate.plugins.SdkMockPlugin" + } } } diff --git a/plugins/library/src/main/java/com/deploygate/plugins/BaseSdkPlugin.kt b/plugins/library/src/main/java/com/deploygate/plugins/BaseSdkPlugin.kt new file mode 100644 index 0000000..2e072ea --- /dev/null +++ b/plugins/library/src/main/java/com/deploygate/plugins/BaseSdkPlugin.kt @@ -0,0 +1,107 @@ +package com.deploygate.plugins + +import com.android.build.api.dsl.LibraryDefaultConfig +import com.android.build.api.dsl.LibraryExtension +import com.deploygate.plugins.dsl.SdkExtension +import com.deploygate.plugins.ext.libraryExtension +import org.gradle.api.GradleException +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.dependencies + +abstract class BaseSdkPlugin : Plugin { + companion object { + /** + * sdk/java/com/deploygate/sdk/HostAppTest.java needs to be changed for a new release + */ + const val ARTIFACT_VERSION = "4.7.1" + + val JAVA_VERSION = JavaVersion.VERSION_1_7 + } + + protected val artifactVersion: String + get() = ARTIFACT_VERSION + + override fun apply(target: Project) { + target.version = ARTIFACT_VERSION + + target.extensions.add("sdk", createSdkExtension()) + + target.apply(plugin = "com.android.library") + target.apply() + + target.libraryExtension.configureLibraryExtension() + + target.tasks.register("verifyReleaseVersion") { + doLast { + if (target.version != System.getenv("RELEASE_VERSION")) { + throw GradleException("${target.version} does not equal to ${System.getenv("RELEASE_VERSION")}") + } + } + } + + target.dependencies { + add("testImplementation", "androidx.test:runner:1.5.2") + add("testImplementation", "androidx.test.ext:junit:1.1.5") + add("testImplementation", "org.robolectric:robolectric:4.10.3") + add("testImplementation", "androidx.test:rules:1.5.0") + add("testImplementation", "com.google.truth:truth:1.0") + } + } + + private fun LibraryExtension.configureLibraryExtension() { + compileSdk = 33 + + defaultConfig { + minSdk = 14 + // TODO remove this property and set the default sdk version for robolectric test instead + @Suppress("DEPRECATION") + targetSdk = 33 + + configureLibraryDefaultConfig() + } + + buildTypes { + release { + isMinifyEnabled = false + } + } + + compileOptions { + sourceCompatibility(JAVA_VERSION) + targetCompatibility(JAVA_VERSION) + } + + testOptions { + unitTests { + isIncludeAndroidResources = true + + all { + it.jvmArgs( + "-Xmx1g", + ) + } + } + } + + buildFeatures { + buildConfig = true + } + + lint { + abortOnError = false + } + + publishing { + singleVariant("release") { + withJavadocJar() + withSourcesJar() + } + } + } + + abstract fun createSdkExtension(): SdkExtension + abstract fun LibraryDefaultConfig.configureLibraryDefaultConfig() +} \ No newline at end of file diff --git a/plugins/library/src/main/java/com/deploygate/plugins/MavenPublishPlugin.kt b/plugins/library/src/main/java/com/deploygate/plugins/MavenPublishPlugin.kt index aa51c8c..c6d1a03 100644 --- a/plugins/library/src/main/java/com/deploygate/plugins/MavenPublishPlugin.kt +++ b/plugins/library/src/main/java/com/deploygate/plugins/MavenPublishPlugin.kt @@ -49,7 +49,7 @@ class MavenPublishPlugin : Plugin { "--aar", variant.packageLibraryProvider.flatMap { it.archiveFile }.get(), "--java", - SdkPlugin.JAVA_VERSION.toString() + BaseSdkPlugin.JAVA_VERSION.toString() ) } } @@ -139,7 +139,7 @@ class MavenPublishPlugin : Plugin { // Configure some values after AGP has been configured named("release") { from(components.getByName("release")) - artifactId = sdkExtension.artifactId.get() + artifactId = sdkExtension.artifactId } } } diff --git a/plugins/library/src/main/java/com/deploygate/plugins/SdkMockPlugin.kt b/plugins/library/src/main/java/com/deploygate/plugins/SdkMockPlugin.kt new file mode 100644 index 0000000..ceb8e9a --- /dev/null +++ b/plugins/library/src/main/java/com/deploygate/plugins/SdkMockPlugin.kt @@ -0,0 +1,19 @@ +package com.deploygate.plugins + +import com.android.build.api.dsl.LibraryDefaultConfig +import com.deploygate.plugins.dsl.SdkExtension +import com.deploygate.plugins.internal.SdkExtensionImpl + +class SdkMockPlugin : BaseSdkPlugin() { + override fun createSdkExtension(): SdkExtension { + return SdkExtensionImpl( + displayName = "DeployGate SDK Mock", + artifactId = "sdk-mock", + description = "Mocked dummy DeployGate SDK for Android to reduce footprint of your release version app without code modification", + ) + } + + override fun LibraryDefaultConfig.configureLibraryDefaultConfig() { + // Do not add meta-data and so on for sdk-mock + } +} \ No newline at end of file diff --git a/plugins/library/src/main/java/com/deploygate/plugins/SdkPlugin.kt b/plugins/library/src/main/java/com/deploygate/plugins/SdkPlugin.kt index 2fb1764..1a4be15 100644 --- a/plugins/library/src/main/java/com/deploygate/plugins/SdkPlugin.kt +++ b/plugins/library/src/main/java/com/deploygate/plugins/SdkPlugin.kt @@ -1,131 +1,80 @@ package com.deploygate.plugins -import com.android.build.api.dsl.LibraryExtension +import com.android.build.api.dsl.LibraryDefaultConfig import com.deploygate.plugins.dsl.SdkExtension -import com.deploygate.plugins.ext.libraryExtension -import org.gradle.api.GradleException -import org.gradle.api.JavaVersion -import org.gradle.api.Plugin +import com.deploygate.plugins.internal.SdkExtensionImpl +import com.deploygate.plugins.tasks.GenerateMetaDataJsonTask import org.gradle.api.Project -import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.register +import java.io.File -class SdkPlugin : Plugin { +class SdkPlugin : BaseSdkPlugin() { companion object { - /** - * sdk/java/com/deploygate/sdk/HostAppTest.java needs to be changed for a new release - */ - private const val ARTIFACT_VERSION = "4.7.1" - - val JAVA_VERSION = JavaVersion.VERSION_1_7 - } - - override fun apply(target: Project) { - target.version = ARTIFACT_VERSION - - target.extensions.create("sdk") - - target.apply(plugin = "com.android.library") - target.apply() - - target.libraryExtension.configureLibraryExtension( - artifactVersion = target.version as String, + // A map of isSupporting> + // The order of elements are important! + private val SUPPORTED_FEATURES = arrayOf( + "UPDATE_MESSAGE_OF_BUILD" to true, + "SERIALIZED_EXCEPTION" to true, + "LOGCAT_BUNDLE" to true, + "STREAMED_LOGCAT" to true, + "DEVICE_CAPTURE" to true, ) - target.tasks.register("verifyReleaseVersion") { - doLast { - if (target.version != System.getenv("RELEASE_VERSION")) { - throw GradleException("${target.version} does not equal to ${System.getenv("RELEASE_VERSION")}") - } - } - } - - target.dependencies { - add("testImplementation", "androidx.test:runner:1.5.2") - add("testImplementation", "androidx.test.ext:junit:1.1.5") - add("testImplementation", "org.robolectric:robolectric:4.10.3") - add("testImplementation", "androidx.test:rules:1.5.0") - add("testImplementation", "com.google.truth:truth:1.0") - } - - } - - fun LibraryExtension.configureLibraryExtension( - artifactVersion: String, - ) { - compileSdk = 33 - - defaultConfig { - minSdk = 14 - targetSdk = 33 - - // A map of isSupporting> - val features = linkedMapOf( - "UPDATE_MESSAGE_OF_BUILD" to true, - "SERIALIZED_EXCEPTION" to true, - "LOGCAT_BUNDLE" to true, - "STREAMED_LOGCAT" to true, - "DEVICE_CAPTURE" to true, - ) - - var flags = 0 - - features.entries.forEachIndexed { i, e -> - val (feature, isSupporting) = e - - buildConfigField("int", feature, "1 << $i") + private val FEATURE_FLAGS: LinkedHashMap = + SUPPORTED_FEATURES.mapIndexed { idx, (feature, _) -> + feature to 1.shl(idx) + }.toMap(LinkedHashMap()) + private val ACTIVE_FEATURE_FLAGS = + SUPPORTED_FEATURES.fold(0) { acc, (feature, isSupporting) -> if (isSupporting) { - flags = flags or 1.shl(i) + acc or FEATURE_FLAGS.getOrElse(feature) { error("$feature is not found in FEATURE_FLAGS") } + } else { + acc } } - addManifestPlaceholders( - mapOf( - "featureFlags" to flags, - "sdkVersion" to "4", - "sdkArtifactVersion" to artifactVersion, - ) - ) - } + private const val KEY_PREFIX = "com.deploygate.sdk." - buildTypes { - release { - isMinifyEnabled = false - } - } + private val META_DATA_ENTRIES = + mapOf( + "deploygate_sdk_feature_flags_name" to "${KEY_PREFIX}feature_flags", + "deploygate_sdk_feature_flags_value" to "$ACTIVE_FEATURE_FLAGS", - compileOptions { - sourceCompatibility(JAVA_VERSION) - targetCompatibility(JAVA_VERSION) - } + "deploygate_sdk_version_name" to "${KEY_PREFIX}version", + "deploygate_sdk_version_value" to "4", - testOptions { - unitTests { - isIncludeAndroidResources = true + "deploygate_sdk_artifact_version_name" to "${KEY_PREFIX}artifact_version", + "deploygate_sdk_artifact_version_value" to ARTIFACT_VERSION, + ) + } - all { - it.jvmArgs( - "-Xmx1g", - ) - } - } + override fun apply(target: Project) { + super.apply(target) + + target.tasks.register("generateMetaDataJson") { + getArtifactVersion().set(ARTIFACT_VERSION) + getFeatureFlags().set(FEATURE_FLAGS) + getActiveFeatureFlags().set(ACTIVE_FEATURE_FLAGS) + getMetaData().set(META_DATA_ENTRIES) + outputFile = + File(target.buildDir, "generated-sdk-metadata/sdk-meta-data-$ARTIFACT_VERSION.json") } + } - buildFeatures { - buildConfig = true - } + override fun createSdkExtension(): SdkExtension { + return SdkExtensionImpl( + displayName = "DeployGate SDK", + artifactId = "sdk", + description = "DeployGate SDK for Android", + ) + } - lint { - abortOnError = false + override fun LibraryDefaultConfig.configureLibraryDefaultConfig() { + FEATURE_FLAGS.forEach { (feature, flag) -> + buildConfigField("int", feature, "$flag") } - publishing { - singleVariant("release") { - withJavadocJar() - withSourcesJar() - } - } + addManifestPlaceholders(META_DATA_ENTRIES) } } \ No newline at end of file diff --git a/plugins/library/src/main/java/com/deploygate/plugins/dsl/SdkExtension.kt b/plugins/library/src/main/java/com/deploygate/plugins/dsl/SdkExtension.kt index 20877ca..df5be56 100644 --- a/plugins/library/src/main/java/com/deploygate/plugins/dsl/SdkExtension.kt +++ b/plugins/library/src/main/java/com/deploygate/plugins/dsl/SdkExtension.kt @@ -1,9 +1,7 @@ package com.deploygate.plugins.dsl -import org.gradle.api.provider.Property - interface SdkExtension { - val artifactId: Property - val displayName: Property - val description: Property + val artifactId: String + val displayName: String + val description: String } \ No newline at end of file diff --git a/plugins/library/src/main/java/com/deploygate/plugins/internal/SdkExtensionImpl.kt b/plugins/library/src/main/java/com/deploygate/plugins/internal/SdkExtensionImpl.kt new file mode 100644 index 0000000..ed6e4ac --- /dev/null +++ b/plugins/library/src/main/java/com/deploygate/plugins/internal/SdkExtensionImpl.kt @@ -0,0 +1,9 @@ +package com.deploygate.plugins.internal + +import com.deploygate.plugins.dsl.SdkExtension + +data class SdkExtensionImpl( + override val artifactId: String, + override val displayName: String, + override val description: String, +) : SdkExtension \ No newline at end of file diff --git a/plugins/library/src/main/java/com/deploygate/plugins/internal/SdkMetaData.kt b/plugins/library/src/main/java/com/deploygate/plugins/internal/SdkMetaData.kt new file mode 100644 index 0000000..c635af9 --- /dev/null +++ b/plugins/library/src/main/java/com/deploygate/plugins/internal/SdkMetaData.kt @@ -0,0 +1,21 @@ +package com.deploygate.plugins.internal + +import com.squareup.moshi.Json + +class SdkMetaData( + @Json(name = "artifact_version") + var artifactVersion: String, + @Json(name = "feature_flags") + var featureFlags: Map, + @Json(name = "active_feature_flags") + var activeFeatureFlags: Int, + @Json(name = "meta_data") + var metaData: Map, +) { + fun validate() { + require(artifactVersion.isNotBlank()) + require(featureFlags.isNotEmpty()) + require(activeFeatureFlags > 0) + require(metaData.isNotEmpty()) + } +} diff --git a/plugins/library/src/main/java/com/deploygate/plugins/tasks/GenerateMetaDataJsonTask.kt b/plugins/library/src/main/java/com/deploygate/plugins/tasks/GenerateMetaDataJsonTask.kt new file mode 100644 index 0000000..22e3e0d --- /dev/null +++ b/plugins/library/src/main/java/com/deploygate/plugins/tasks/GenerateMetaDataJsonTask.kt @@ -0,0 +1,70 @@ +package com.deploygate.plugins.tasks + +import com.deploygate.plugins.internal.SdkMetaData +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.plugins.ide.api.GeneratorTask +import org.gradle.plugins.ide.internal.generator.generator.Generator +import java.io.File + +abstract class GenerateMetaDataJsonTask : GeneratorTask() { + @Input + abstract fun getArtifactVersion(): Property + + @Input + abstract fun getFeatureFlags(): MapProperty + + @Input + abstract fun getActiveFeatureFlags(): Property + + @Input + abstract fun getMetaData(): MapProperty + + init { + generator = object : Generator { + override fun read(inputFile: File): SdkMetaData { + return sdkMetaDataAdapter.fromJson(inputFile.readText())!! + } + + override fun defaultInstance(): SdkMetaData { + return SdkMetaData( + artifactVersion = "", + featureFlags = emptyMap(), + metaData = emptyMap(), + activeFeatureFlags = 0, + ) + } + + override fun write(`object`: SdkMetaData, outputFile: File) { + outputFile.writeText( + text = sdkMetaDataAdapter.toJson(`object`), + charset = Charsets.UTF_8, + ) + } + + override fun configure(`object`: SdkMetaData) { + `object`.apply { + this.artifactVersion = getArtifactVersion().get() + this.featureFlags = getFeatureFlags().get() + this.activeFeatureFlags = getActiveFeatureFlags().get() + this.metaData = getMetaData().get() + } + + `object`.validate() + } + } + } + + companion object { + private val sdkMetaDataAdapter: JsonAdapter = Moshi.Builder() + .addLast(KotlinJsonAdapterFactory()) + .build() + .adapter(SdkMetaData::class.java) + .failOnUnknown() + .indent(" ") + } +} \ No newline at end of file diff --git a/sdk/build.gradle b/sdk/build.gradle index 0a273f5..e6d0dc8 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -10,9 +10,3 @@ dependencies { testImplementation 'org.mockito:mockito-core:4.4.0' testImplementation 'org.mockito:mockito-inline:4.4.0' } - -sdk { - displayName.set("DeployGate SDK") - artifactId.set('sdk') - description.set('DeployGate SDK for Android') -} diff --git a/sdk/src/main/AndroidManifest.xml b/sdk/src/main/AndroidManifest.xml index 3492e35..f66b050 100644 --- a/sdk/src/main/AndroidManifest.xml +++ b/sdk/src/main/AndroidManifest.xml @@ -10,18 +10,18 @@ /> diff --git a/sdkMock/build.gradle b/sdkMock/build.gradle index 79be5a2..e4cecfe 100644 --- a/sdkMock/build.gradle +++ b/sdkMock/build.gradle @@ -1,7 +1 @@ -apply plugin: 'com.deploygate.plugins.sdk' - -sdk { - displayName.set("DeployGate SDK Mock") - artifactId.set('sdk-mock') - description.set('Mocked dummy DeployGate SDK for Android to reduce footprint of your release version app without code modification') -} +apply plugin: 'com.deploygate.plugins.sdk-mock'