Skip to content

Commit

Permalink
[distribution] Add Gradle plugin for distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
chromy committed Oct 25, 2024
1 parent c289b47 commit b4a7497
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 14 deletions.
4 changes: 4 additions & 0 deletions gradle-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

- Add build distribution support to Gradle plugin. [#281](https://github.com/EmergeTools/emerge-android/pull/281)

## 4.0.2 - 2024-10-22

- Remove `previousSha` from PR
Expand Down
73 changes: 67 additions & 6 deletions gradle-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,10 @@ emerge {
// The build variants Reaper is enabled for.
// When Reaper is enabled the application bytecode will be instrumented to support Reaper.
enabledVariants.set(listOf("release", "releaseVariant2"))
// The key used to identify Reaper reports for your organization. Emerge recommends setting this as an environment variable
// Note: This key is not the same as the API key used for uploading to Emerge - you can find this
publishableApiKey.set(System.getenv("REAPER_API_TOKEN"))
// The key used to identify Reaper reports for your organization. Emerge recommends setting this as an environment variable.
// This key can be found at https://www.emergetools.com/settings?tab=feature-configuration&cards=reaper_enabled
// Note: This key is not the same as the API token used for uploading to Emerge.
publishableApiKey.set(System.getenv("REAPER_API_KEY"))

// Optional, defaults to 'release'
tag.set("release")
Expand All @@ -273,6 +274,51 @@ emerge {
| `enabledVariants` | `List<String>` | `emptyList()` | The build variants Reaper is enabled for. |
| `tag` | `String` | `release` | The build tag to use for grouping builds in the Emerge dashboard. |

### Distribution

The `distribution` extension allows you to configure build distribution specific fields.

See the [build distribution](https://docs.emergetools.com/docs/distribution-setup-android) docs for more information.

#### Tasks

| Task | Description |
|----------------------------------------|------------------------------------------------------------------------------------------------|
| `emergeDistributionPreflight{Variant}` | Run a preflight check to validate if distribution is properly set up for the specific variant. |

#### Configuration

The `distribution` extension allows you to configure Distribution-specific fields.

```kotlin
emerge {
// ..

distribution {
// The build variants Distribution is enabled for.
enabledVariants.set(listOf("release", "staging"))
// The key used to authenticate downloads for future updates.
// Emerge recommends setting this as an environment variable.
// This key can be found at https://www.emergetools.com/settings?tab=feature-configuration&cards=distribution_enabled
// Note: This key is not the same as the API token used for uploading to Emerge.
apiKey.set(System.getenv("DISTRIBUTION_API_KEY"))

// Optional, defaults to 'release'
tag.set("release")
// Alternatively, use `setFromVariant()` to set the tag from the Android build variant name
tag.setFromVariant()
}
}
```

##### Fields

| Field | Type | Default | Description |
|---------------------|----------------|---------------|-----------------------------------------------------------------------------|
| `apiKey` | `String` | | This key is used to authenticate update downloads. |
| `enabledVariants` | `List<String>` | `emptyList()` | The build variants Distribution is enabled for. |
| `tag` | `String` | `release` | The build tag to use for determining which builds are possible updates. |

### Performance

#### Tasks
Expand Down Expand Up @@ -391,15 +437,30 @@ emerge {
// The build variants Reaper is enabled for.
// When Reaper is enabled the application bytecode will be instrumented to support Reaper.
enabledVariants.set(listOf("release", "releaseVariant2"))
// The key used to identify Reaper reports for your organization. Emerge recommends setting this as an environment variable
// Note: This key is not the same as the API key used for uploading to Emerge - you can find this
publishableApiKey.set(System.getenv("REAPER_API_TOKEN"))
// The key used to identify Reaper reports for your organization. Emerge recommends setting this as an environment variable.
// This key can be found at https://www.emergetools.com/settings?tab=feature-configuration&cards=reaper_enabled
// Note: This key is not the same as the API token used for uploading to Emerge.
publishableApiKey.set(System.getenv("REAPER_API_KEY"))

// Optional, defaults to 'release'
tag.set("release")
// Alternatively, use `setFromVariant()` to set the tag from the Android build variant name
tag.setFromVariant()
}

distribution {
// The build variants Distribution is enabled for.
enabledVariants.set(listOf("release", "staging"))
// The key used to authenticate downloads for future updates.
// Emerge recommends setting this as an environment variable.
// This key can be found at https://www.emergetools.com/settings?tab=feature-configuration&cards=distribution_enabled
// Note: This key is not the same as the API token used for uploading to Emerge.
apiKey.set(System.getenv("DISTRIBUTION_API_KEY"))

// Optional, defaults to 'release'
tag.set("release")
// Alternatively, use `setFromVariant()` to set the tag from the Android build variant name
tag.setFromVariant()
}

performance {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.android.build.api.variant.ApplicationVariant
import com.android.build.api.variant.TestAndroidComponentsExtension
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import com.emergetools.android.gradle.instrumentation.reaper.ReaperClassLoadClassVisitorFactory
import com.emergetools.android.gradle.tasks.distribution.registerDistributionTasks
import com.emergetools.android.gradle.tasks.internal.SaveExtensionConfigTask
import com.emergetools.android.gradle.tasks.perf.registerGeneratePerfProjectTask
import com.emergetools.android.gradle.tasks.perf.registerPerformanceTasks
Expand Down Expand Up @@ -96,9 +97,9 @@ class EmergePlugin : Plugin<Project> {
registerSizeTasks(appProject, emergeExtension, variant)
}

// Always register the Reaper initialization task even if Reaper is disabled since users use
// it to help get Reaper setup for the first time.
// Reaper and distribution handle the enabled checks themselves:
registerReaperTasks(appProject, emergeExtension, variant)
registerDistributionTasks(appProject, emergeExtension, variant)

registerReaperTransform(
project = appProject,
Expand Down Expand Up @@ -290,6 +291,17 @@ class EmergePlugin : Plugin<Project> {
)
addItem("tag (optional): ${extension.reaperOptions.tag.orEmpty()}", reaperHeading)

val distributionHeading = addHeading("distribution")
addItem(
"enabledVariants: ${extension.distributionOptions.enabledVariants.getOrElse(emptyList())}",
distributionHeading
)
addItem(
"apiKey: ${if (extension.distributionOptions.apiKey.isPresent) "*****" else "MISSING"}",
distributionHeading
)
addItem("tag (optional): ${extension.distributionOptions.tag.orEmpty()}", distributionHeading)

val performanceHeading = addHeading("performance")
addItem("projectPath: ${extension.perfOptions.projectPath.orEmpty()}", performanceHeading)
addItem("tag (optional): ${extension.perfOptions.tag.orEmpty()}", performanceHeading)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ abstract class EmergePluginExtension @Inject constructor(objects: ObjectFactory)
action.execute(reaperOptions)
}

@get:Nested
abstract val distributionOptions: DistributionOptions

fun distribution(action: Action<DistributionOptions>) {
action.execute(distributionOptions)
}

@get:Nested
abstract val vcsOptions: VCSOptions

Expand Down Expand Up @@ -183,3 +190,9 @@ abstract class ReaperOptions : ProductOptions() {

abstract val publishableApiKey: Property<String>
}

abstract class DistributionOptions : ProductOptions() {
abstract val enabledVariants: ListProperty<String>

abstract val apiKey: Property<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.emergetools.android.gradle.tasks.distribution

import com.emergetools.android.gradle.tasks.base.BasePreflightTask
import com.emergetools.android.gradle.util.preflight.Preflight
import com.emergetools.android.gradle.util.preflight.PreflightFailure
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction

abstract class DistributionPreflight : BasePreflightTask() {

@get:Input
@get:Optional
abstract val hasEmergeApiToken: Property<Boolean>

@get:Input
@get:Optional
abstract val distributionApiKey: Property<String>

@get:Input
@get:Optional
abstract val distributionTag: Property<String>

@get:Input
@get:Optional
abstract val distributionEnabled: Property<Boolean>

@get:Input
abstract val variantName: Property<String>

@get:Input
abstract val hasDistributionImplementationDependency: Property<Boolean>

@TaskAction
fun execute() {
val preflight = Preflight("Reaper preflight check")

val hasEmergeApiToken = hasEmergeApiToken.getOrElse(false)
preflight.add("Emerge API token set") {
if (!hasEmergeApiToken) {
throw PreflightFailure("Emerge API token not set. See https://docs.emergetools.com/docs/uploading-basics#obtain-an-api-key")
}
}

val variantName = variantName.get()
preflight.add("enabled for variant: $variantName") {
if (!distributionEnabled.getOrElse(false)) {
throw PreflightFailure("Distribution not enabled for variant $variantName. Make sure \"${variantName}\" is included in `distribution.enabledVariants`")
}
}

preflight.add("apiKey set") {
val key = distributionApiKey.orNull
if (key == null) {
throw PreflightFailure("apiKey not set. See https://docs.emergetools.com/docs/distribution-setup-android#configure-the-sdk")
}
if (key == "") {
throw PreflightFailure("apiKey must not be empty. See https://docs.emergetools.com/docs/distribution-setup-android#configure-the-sdk")
}
}

preflight.add("Runtime SDK added") {
if (!hasDistributionImplementationDependency.getOrElse(false)) {
throw PreflightFailure("Distribution runtime SDK missing as an implementation dependency. See https://docs.emergetools.com/docs/distribution-setup-android#install-the-sdk")
}
}

preflight.addSubPreflight(buildVcsPreflight())
preflight.logOutput(logger)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import com.emergetools.android.gradle.util.capitalize
import com.emergetools.android.gradle.util.hasDependency
import org.gradle.api.Project

const val EMERGE_REAPER_TASK_GROUP = "Emerge reaper"
const val REAPER_DEP_GROUP = "com.emergetools.reaper"
const val REAPER_DEP_NAME = "reaper"
private const val EMERGE_REAPER_TASK_GROUP = "Emerge reaper"
private const val REAPER_DEP_GROUP = "com.emergetools.reaper"
private const val REAPER_DEP_NAME = "reaper"

fun registerReaperTasks(
appProject: Project,
extension: EmergePluginExtension,
variant: Variant,
) {
appProject.logger.debug(
"Registering reaper tasks for variant ${variant.name} in project ${appProject.path}"
"Registering Reaper tasks for variant ${variant.name} in project ${appProject.path}"
)

registerReaperPreflightTask(appProject, extension, variant)
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ runtime-android = "1.7.3"
foundation-layout-android = "1.7.3"

# internal
emerge-gradle-plugin = "4.0.2"
emerge-gradle-plugin = "4.0.3"
emerge-performance = "2.1.2"
emerge-reaper = "1.0.0-rc03"
emerge-snapshots = "1.3.0-rc02"
emerge-distribution = "0.0.1"
emerge-distribution = "0.0.2"

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
Expand Down

0 comments on commit b4a7497

Please sign in to comment.