Skip to content

Commit

Permalink
Merge branch 'main' into renovate/kotlin-monorepo
Browse files Browse the repository at this point in the history
  • Loading branch information
gastonfournier authored Jul 25, 2024
2 parents 65b0356 + f1589ce commit 34ff715
Show file tree
Hide file tree
Showing 50 changed files with 903 additions and 617 deletions.
30 changes: 22 additions & 8 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,31 @@ jobs:
steps:
- uses: actions/checkout@v4
name: Checkout code
with:
fetch-depth: 2 # Checkout HEAD^
- name: Setup JDK
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'temurin'
cache: gradle
- name: Build and test
run: ./gradlew build
# TODO configure jacocoTestReport and coverallsJacoco
#- name: Run jacocoTestReport
# if: github.ref == 'refs/heads/main'
# env:
# COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
# run: ./gradlew jacocoTestReport coverallsJacoco
- name: Check for changes in app directory
id: check-changes
run: |
CHANGED=$(git diff --name-only HEAD^...HEAD -- app/)
if [ -z "$CHANGED" ]; then
echo "No changes in app/ directory."
echo "skip-build-app=true" >> $GITHUB_ENV
fi
- name: Build and test SDK
if: env.skip-build-app == 'true'
run: ./gradlew unleashandroidsdk:build unleashandroidsdk:jacocoTestReport
- name: Build and test all
if: env.skip-build-app != 'true'
run: ./gradlew build jacocoTestReport
- name: Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
allow-empty: true
base-path: unleashandroidsdk/src/main/java
41 changes: 41 additions & 0 deletions .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Create a new release tag

on:
workflow_dispatch:
inputs:
release:
description: 'Release version'
required: true
type: choice
options:
- pre-release
- patch
- minor
- major

permissions:
contents: write
actions: write

jobs:
create-tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
name: Checkout code
with:
fetch-depth: 0
- name: Setup JDK
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'temurin'
cache: gradle
- run: ./gradlew release -Prelease.versionIncrementer=incrementMajor
if: github.event.inputs.release == 'major'
- run: ./gradlew release -Prelease.versionIncrementer=incrementMinor
if: github.event.inputs.release == 'minor'
- run: ./gradlew release -Prelease.versionIncrementer=incrementPatch
if: github.event.inputs.release == 'patch'
- run: ./gradlew release -Prelease.versionIncrementer=incrementPrerelease -Prelease.versionIncrementer.initialPreReleaseIfNotOnPrerelease=-rc1
if: github.event.inputs.release == 'pre-release'
24 changes: 22 additions & 2 deletions .github/workflows/prs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,31 @@ jobs:
steps:
- uses: actions/checkout@v4
name: Checkout code
with:
fetch-depth: 0
- name: Setup JDK
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'temurin'
cache: gradle
- name: Build and test
run: ./gradlew build
- name: Check for changes in app directory
id: check-changes
run: |
CHANGED=$(git diff --name-only origin/main...HEAD -- app/)
if [ -z "$CHANGED" ]; then
echo "No changes in app/ directory."
echo "skip-build-app=true" >> $GITHUB_ENV
fi
- name: Build and test SDK
if: env.skip-build-app == 'true'
run: ./gradlew unleashandroidsdk:build unleashandroidsdk:jacocoTestReport
- name: Build and test all
if: env.skip-build-app != 'true'
run: ./gradlew build jacocoTestReport
- name: Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
allow-empty: true
base-path: unleashandroidsdk/src/main/java
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
tags:
- 'v*'
workflow_run:
workflows: ["Create a new release tag"]
types:
- completed

jobs:
deploy-release:
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@

## Getting started

This is the Android SDK for Unleash Proxy. It is a lightweight SDK that allows you to connect to the Unleash Proxy and fetch feature toggles.
This is the Android SDK for [Unleash Frontend API](https://docs.getunleash.io/reference/front-end-api) provided by the [Unleash server](https://github.com/Unleash/unleash) or [Unleash Edge](https://github.com/Unleash/unleash-edge). It is a lightweight SDK that allows you to connect to the Unleash Proxy and fetch feature toggles.

This supersedes the [previous Unleash Android Proxy SDK](https://github.com/Unleash/unleash-android-proxy-sdk/) this one is a an Android library instead of a Java library.

It's not a drop-in replacement of the previous one, so it requires code changes to use it.

**What are the benefits of migrating?**
1. This SDK will respect the Android lifecycle and stop polling when the app is in the background.
2. It will also respect the network state and only poll when the device is connected to the internet.
1. Respects the Android lifecycle and stops polling and sending metrics in the background.
2. Monitors network connectivity to avoid unnecessary polling (requires API level 23 or above).
3. Uses the native Android logging system instead of SLF4J.
4. Respects the minimum Android API level 21, but we recommend API level 23.

### Step 1

Expand Down
117 changes: 117 additions & 0 deletions docs/MigrationGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Migration Guide from unleash-android-proxy-sdk

This guide provides detailed steps for migrating your project from the Unleash Android Proxy SDK version to the newer Unleash Android SDK.

We will focus on the [previous sample application](https://github.com/Unleash/unleash-android-proxy-sdk/tree/main/samples/android), specifically highlighting the changes from this pull request: https://github.com/Unleash/unleash-android-proxy-sdk/pull/83

## Benefits of Migrating

This version of the Unleash Android SDK introduces several improvements, including:
- Uses the native Android logging system instead of SLF4J.
- Respects the Android lifecycle and stops polling and sending metrics in the background.
- Respects the minimum Android API level 21, but we recommend API level 23.
- Monitors network connectivity to avoid unnecessary polling (requires API level 23 or above).

## Overview

The new SDK introduces several changes and improvements, including API modifications and a new initialization process.

## Step-by-Step Migration

### 1. Update Gradle Dependency

First, update the dependency in your `build.gradle` file:

```gradle
dependencies {
// Remove the old SDK
implementation 'io.getunleash:unleash-android-proxy-sdk:0.5.0'
// Add the new SDK
implementation 'io.getunleash:unleash-android:$version'
}
```

### 2. Update the initialization code
We won't cover all the details here as most of the configuration can be set using the builders fluent methods. However, the main difference is that the new SDK requires an `Application` context to be passed to the `Unleash` constructor. This is necessary to monitor the network connectivity and respect the Android lifecycle. If you use hilt, this can be injected with `@ApplicationContext context`.

#### Unleash context initialization
The main differences are:
1. The application name is no longer configurable through the context, as it is constant throughout the application's lifetime. The `appName` should be set using the `UnleashConfig` builder.
2. The instance ID is no longer configurable. The SDK will generate a unique instance ID for each instance.
3. Update the import statements to use the new SDK classes.

```kotlin
val unleashContext = UnleashContext.newBuilder()
// .appName("unleash-android") // remove this line
// .instanceId("main-activity-unleash-demo-${Random.nextLong()}") // remove this line
.userId("unleash_demo_user")
.sessionId(Random.nextLong().toString())
.build()
```

#### Unleash configuration
The main differences are:
1. Metrics are enabled by default.
2. App name is now a mandatory parameter to the builder.
3. Instance id is no longer configurable.
4. The polling mode is now a polling strategy with a fluent API.
5. The metrics interval is now part of the metrics strategy with a fluent API.

**Old SDK**
```kotlin
UnleashConfig.newBuilder()
.appName("unleash-android")
.instanceId("unleash-android-${Random.nextLong()}")
.enableMetrics()
.clientKey("xyz")
.proxyUrl("https://eu.app.unleash-hosted.com/demo/api/frontend")
.pollingMode(
PollingModes.autoPoll(
autoPollIntervalSeconds = 15
) {

}
)
.metricsInterval(5000)
.build()
```

**New SDK**
```kotlin
UnleashConfig.newBuilder("unleash-android")
.clientKey("xyz")
.proxyUrl("https://eu.app.unleash-hosted.com/demo/api/frontend")
.pollingStrategy.interval(15000)
.metricsStrategy.interval(5000)
.build()
```

#### Creating the Unleash instance
The previous SDK used a builder to construct the Unleash instance while the new SDK relies on constructor parameters. There are also other meaningful changes:

1. The new SDK does not start automatically. You need to call `unleash.start()` to start the polling and metrics collection.
2. The new SDK accepts event listeners at the constructor level or as parameters when calling `unleash.start()` (you can also edit your config object setting `delayedInitialization` to false).
3. The interface `UnleashClientSpec` is now `Unleash`.

```kotlin
UnleashClient.newBuilder()
.unleashConfig(unleashConfig)
.unleashContext(unleashContext)
.build()
```

**New SDK**
_Note:_ Android context is now required to be passed to the Unleash constructor and you will usually want it to be bound to the application context.

```kotlin
val unleash = DefaultUnleash(
androidContext = context,
unleashConfig = unleashConfig,
unleashContext = unleashContext
)
unleash.start()
```

#### Updating class references
Most of the classes have been moved to `io.getunleash.android` package. Update the import statements in your classes.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ agp = "8.5.1"
kotlin = "1.9.25"
coreKtx = "1.13.1"
junit = "4.13.2"
jsonunit = "3.4.1"
androidxTestExt = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
Expand Down Expand Up @@ -39,6 +40,7 @@ jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-core", ve
jackson-module-kotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson" }
jackson-datatype-jsr310 = { group = "com.fasterxml.jackson.datatype", name = "jackson-datatype-jsr310", version.ref = "jackson" }
assertj = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" }
jsonunit = { group = "net.javacrumbs.json-unit", name = "json-unit-assertj", version.ref = "jsonunit" }

## sample app
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
Expand Down
60 changes: 46 additions & 14 deletions unleashandroidsdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ plugins {
alias(libs.plugins.jetbrains.kotlin.android)
id("org.jetbrains.dokka") version "1.9.20"
id("pl.allegro.tech.build.axion-release") version "1.18.2"
jacoco
}

val tagVersion = System.getenv("GITHUB_REF")?.split('/')?.last()
project.version = scmVersion.version

jacoco {
toolVersion = "0.8.12"
}

android {
namespace = "io.getunleash.android"
compileSdk = 34
Expand All @@ -29,7 +34,7 @@ android {

buildTypes {
debug {

isMinifyEnabled = false
}
release {
isMinifyEnabled = false
Expand All @@ -48,9 +53,8 @@ android {
}

publishing {
multipleVariants {
includeBuildTypeValues("debug", "release")
allVariants()
singleVariant("release") {
withSourcesJar()
withJavadocJar()
}
}
Expand All @@ -59,8 +63,6 @@ android {
dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.work.ktx)
implementation(libs.androidx.lifecycle.process)
implementation(libs.jackson.databind)
implementation(libs.jackson.core)
Expand All @@ -75,13 +77,7 @@ dependencies {
testImplementation(libs.robolectric.test)
testImplementation(libs.okhttp.mockserver)
testImplementation(libs.awaitility)
androidTestImplementation(libs.kotlinx.coroutines.test)
androidTestImplementation(libs.assertj)
androidTestImplementation(libs.mockito)
androidTestImplementation(libs.androidx.work.testing)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(libs.okhttp.mockserver)
testImplementation(libs.jsonunit)
}

publishing {
Expand Down Expand Up @@ -160,4 +156,40 @@ tasks.withType<DokkaTask>().configureEach {
}
}
}
}
}

val jacocoTestReport by tasks.register<JacocoReport>("jacocoTestReport") {
dependsOn("testDebugUnitTest")

reports {
xml.required.set(true)
html.required.set(true)
}

val fileTreeConfig: (ConfigurableFileTree) -> Unit = {
it.exclude("**/R.class", "**/R$*.class", "**/BuildConfig.*", "**/Manifest*.*", "android/**/*.*",
"**/data/**", "**/errors/**", "**/events/**")
}

sourceDirectories.setFrom(files("${projectDir}/src/main/java"))
classDirectories.setFrom(listOf(
fileTree("${buildDir}/tmp/kotlin-classes/debug", fileTreeConfig)
))
executionData.setFrom(fileTree(buildDir) {
include("jacoco/*.exec")
})
}

tasks.withType<Test> {
testLogging {
showExceptions = true
showStackTraces = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
events("passed", "skipped", "failed")
}
configure<JacocoTaskExtension> {
isIncludeNoLocationClasses = true
excludes = listOf("jdk.internal.*")
}
finalizedBy(jacocoTestReport)
}
Loading

0 comments on commit 34ff715

Please sign in to comment.