Skip to content

Commit

Permalink
Merge pull request #12 from dzmpr/feat/TRCKR-T-5_support_multiplatform
Browse files Browse the repository at this point in the history
TRCKR-T-5 add multiplatform support
  • Loading branch information
dzmpr authored May 7, 2023
2 parents 1523612 + 09916ac commit b046f0d
Show file tree
Hide file tree
Showing 55 changed files with 204 additions and 100 deletions.
15 changes: 6 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
jobs:
publish:
name: Publish artifacts
runs-on: ubuntu-latest
runs-on: macos-latest

steps:
- name: Checkout
Expand All @@ -15,7 +15,7 @@ jobs:
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
distribution: 'adopt'
distribution: 'temurin'
java-version: '8'

- name: Publish artifacts to maven central
Expand All @@ -41,12 +41,9 @@ jobs:
echo "version=$version" >> $GITHUB_ENV
- name: Create release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: softprops/action-gh-release@v1
with:
commitish: ${{ github.ref }}
body_path: ${{ github.workspace }}/changelog.md
name: v${{ env.version }}
tag_name: v${{ env.version }}
release_name: v${{ env.version }}
body: "Will be filled later."
draft: true
token: ${{ secrets.GITHUB_TOKEN }}
32 changes: 14 additions & 18 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
name: Tests

# Controls when the workflow will run
on:
# Triggers the workflow pull request events but only for the "main" branch
pull_request:
branches: [ "main" ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
tests:
name: Run unit tests
runs-on: macos-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
- name: Set up JDK 11
- name: Checkout
uses: actions/checkout@v3

- name: Set up JDK 8
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '11'
- name: Test with Gradle
run: ./gradlew test
distribution: 'temurin'
java-version: '8'

- name: Run tests
# Temporary run tests only for JVM target, because ios/watchos/tvos tests fail.
# TODO: https://youtrack.jetbrains.com/issue/KT-54814
run: ./gradlew jvmTest
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[![Maven Central](https://maven-badges.herokuapp.com/maven-central/ru.cookedapp.trckr/trckr-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ru.cookedapp.trckr/trckr-core)
[![CI](https://github.com/dzmpr/trckr/actions/workflows/tests.yml/badge.svg)](https://github.com/dzmpr/trckr/actions/workflows/tests.yml)
[![KMM](https://img.shields.io/badge/KMM-supported-orange)](https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

Trckr is **Kotlin Symbol Processor** to help you send analytics to multiple destinations (called adapters).
Expand Down Expand Up @@ -62,8 +63,11 @@ dependencies {

To access generated code from KSP, you need to set up the source path into your module's `build.gradle.kts` file:
```kotlin
sourceSets.configureEach {
kotlin.srcDir("$buildDir/generated/ksp/$name/kotlin/")
kotlin {
// ...
sourceSets.configureEach {
kotlin.srcDir("$buildDir/generated/ksp/$name/kotlin/")
}
}
```

Expand Down
2 changes: 0 additions & 2 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ plugins {
}

repositories {
mavenCentral()
gradlePluginPortal()
}

dependencies {
implementation(libs.kotlin.plugin)
implementation(libs.publishing.plugin)
}
1 change: 0 additions & 1 deletion build-logic/src/main/kotlin/trckr-artifact.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import com.vanniktech.maven.publish.SonatypeHost
import ru.cookedapp.trckr.gradle.isVersionStringValid

plugins {
id("trckr-module")
id("com.vanniktech.maven.publish")
}

Expand Down
13 changes: 0 additions & 13 deletions build-logic/src/main/kotlin/trckr-module.gradle.kts

This file was deleted.

1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
plugins {
alias(libs.plugins.ksp) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
}

allprojects {
Expand Down
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### Changelog
* Add kotlin multiplatform support.

### Dependencies
| Dependency | Version |
|------------|:--------------:|
| Kotlin | `1.7.20` |
| KSP | `1.7.20-1.0.7` |
2 changes: 1 addition & 1 deletion libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.re
kotlinpoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinpoet" }
kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlinpoet" }
# Compiled plugins
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
publishing-plugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "publishing" }
# Test dependencies
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
Expand All @@ -27,4 +26,5 @@ kotlinpoet = ["kotlinpoet", "kotlinpoet-ksp"]

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
59 changes: 56 additions & 3 deletions trckr-core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,61 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.kotlin.multiplatform)
id("trckr-artifact")
}

dependencies {
testImplementation(libs.kotlin.test)
testImplementation(libs.mockk)
kotlin {
// Targets

// JVM target
jvm {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
// JS target
// TODO: Currently not support arrays in annotations
// js(BOTH) {
// browser()
// nodejs()
// }
// iOS targets
iosX64()
iosArm64()
iosSimulatorArm64()
// watchOS targets
watchosArm32()
watchosArm64()
watchosX64()
watchosSimulatorArm64()
// tvOS targets
tvosArm64()
tvosX64()
tvosSimulatorArm64()
// macOS targets
macosX64()
macosArm64()
// Linux targets
linuxArm64()
linuxX64()
// MinGW targets
mingwX64()

// SourceSets
sourceSets {
commonTest {
dependencies {
implementation(libs.kotlin.test)
}
}
}
}

tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package ru.cookedapp.trckr.core

import kotlin.test.Test
import kotlin.test.assertFailsWith
import org.junit.jupiter.api.Test
import ru.cookedapp.trckr.core.exceptions.TrckrBuilderException
import ru.cookedapp.trckr.core.testHelpers.FirstAdapter

internal class TrckrBuilderTest {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package ru.cookedapp.trckr.core

import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.verify
import kotlin.reflect.KClass
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import org.junit.jupiter.api.Test
import ru.cookedapp.trckr.core.adapter.TrackerAdapter
import ru.cookedapp.trckr.core.annotations.data.TrackStrategy
import ru.cookedapp.trckr.core.converter.ParameterConverter
import ru.cookedapp.trckr.core.converter.TypeConverter
import ru.cookedapp.trckr.core.event.TrckrEvent
import ru.cookedapp.trckr.core.exceptions.TrckrConversionException
import ru.cookedapp.trckr.core.param.TrckrParam
import ru.cookedapp.trckr.core.testHelpers.FakeParameterConverter
import ru.cookedapp.trckr.core.testHelpers.FakeTypeConverter
import ru.cookedapp.trckr.core.testHelpers.FirstAdapter
import ru.cookedapp.trckr.core.testHelpers.SecondAdapter
import ru.cookedapp.trckr.core.testHelpers.createFakeAdapter

class TrckrCoreTest {

Expand All @@ -31,7 +32,7 @@ class TrckrCoreTest {
trackToSecondAdapter = true,
)
}

@Test
fun `should track event to all adapters except skipped adapters`() {
testTrackToAdapters(
Expand Down Expand Up @@ -140,7 +141,7 @@ class TrckrCoreTest {
strategy: TrackStrategy,
expectedParameter: Pair<String, Any?>?,
) {
val adapter = createAdapter<TrackerAdapter>()
val adapter = createFakeAdapter()
val event = createEvent(
parameters = listOf(TrckrParam(defaultParameterName, strategy, value)),
)
Expand All @@ -153,15 +154,17 @@ class TrckrCoreTest {
tracker.track(event)

val expectedParameters = expectedParameter?.let { mapOf(expectedParameter) } ?: emptyMap()
verify { adapter.trackEvent(event.name, expectedParameters) }
val expectedEvents = listOf(event.name to expectedParameters)
val actualEvents = adapter.getEvents()
assertEquals(expectedEvents, actualEvents)
}

private fun testValueConversion(
parameterConverter: ParameterConverter?,
typeConverter: TypeConverter?,
convertedValue: Any?,
) {
val adapter = createAdapter<TrackerAdapter>()
val adapter = createFakeAdapter()
val parameter = TrckrParam(
name = defaultParameterName,
strategy = TrackStrategy.DEFAULT,
Expand All @@ -177,7 +180,9 @@ class TrckrCoreTest {
tracker.track(event)

val expectedParameters = mapOf(defaultParameterName to convertedValue)
verify { adapter.trackEvent(event.name, expectedParameters) }
val expectedEvents = listOf(event.name to expectedParameters)
val actualEvents = adapter.getEvents()
assertEquals(expectedEvents, actualEvents)
}

private fun testTrackToAdapters(
Expand All @@ -186,26 +191,29 @@ class TrckrCoreTest {
trackToFirstAdapter: Boolean,
trackToSecondAdapter: Boolean,
) {
val firstAdapter = createAdapter<FirstAdapter>()
val secondAdapter = createAdapter<SecondAdapter>()
val firstAdapter = createFakeAdapter()
val firstAdapterImpl = object : TrackerAdapter by firstAdapter, FirstAdapter {}
val secondAdapter = createFakeAdapter()
val secondAdapterImpl = object : TrackerAdapter by secondAdapter, SecondAdapter {}
val event = createEvent(skipAdapters = buildList {
if (skipFirstAdapter) add(FirstAdapter::class)
if (skipSecondAdapter) add(SecondAdapter::class)
})
val tracker = createTrckrCore(adapters = listOf(firstAdapter, secondAdapter))
val tracker = createTrckrCore(adapters = listOf(firstAdapterImpl, secondAdapterImpl))

tracker.track(event)

val firstAdapterCallCount = if (trackToFirstAdapter) 1 else 0
verify(exactly = firstAdapterCallCount) {
firstAdapter.trackEvent(event.name, parameters = emptyMap())
}
val secondAdapterCallCount = if (trackToSecondAdapter) 1 else 0
verify(exactly = secondAdapterCallCount) {
secondAdapter.trackEvent(event.name, parameters = emptyMap())
}
val expectedEvents = listOf(event.name to emptyMap<String, Any?>())
val expectedFirstAdaptersEvents = if (trackToFirstAdapter) expectedEvents else emptyList()
assertEquals(expectedFirstAdaptersEvents, firstAdapter.getEvents())
val expectedSecondAdapterEvents = if (trackToSecondAdapter) expectedEvents else emptyList()
assertEquals(expectedSecondAdapterEvents, secondAdapter.getEvents())
}

private fun createTypeConverter() = FakeTypeConverter(typeConverterResult)

private fun createParameterConverter() = FakeParameterConverter(parameterConverterResult)

private fun createEvent(
skipAdapters: List<KClass<out TrackerAdapter>> = emptyList(),
parameters: List<TrckrParam> = emptyList(),
Expand All @@ -215,18 +223,6 @@ class TrckrCoreTest {
parameters = parameters,
)

private inline fun <reified A : TrackerAdapter> createAdapter() = mockk<A>().also { adapter ->
every { adapter.trackEvent(any(), any()) } just Runs
}

private fun createTypeConverter() = mockk<TypeConverter>().also { converter ->
every { converter.convert(any()) } returns typeConverterResult
}

private fun createParameterConverter() = mockk<ParameterConverter>().also { converter ->
every { converter.convert(any(), any(), any()) } returns parameterConverterResult
}

private fun createTrckrCore(
adapters: List<TrackerAdapter> = emptyList(),
typeConverters: List<TypeConverter> = emptyList(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.cookedapp.trckr.core.testHelpers

import ru.cookedapp.trckr.core.adapter.TrackerAdapter

internal interface FirstAdapter : TrackerAdapter

internal interface SecondAdapter : TrackerAdapter
Loading

0 comments on commit b046f0d

Please sign in to comment.