diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dc2412f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI + +on: + pull_request: + push: + branches: [master] + +jobs: + test: + runs-on: macos-latest + timeout-minutes: 60 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Java + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 + + - name: Run tests + run: ./gradlew :signaturepad:allTests diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2ffbf6b..a22c283 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,7 +26,7 @@ jobs: run: ./gradlew :signaturepad:build - name: Publish release - run: ./gradlew publishToMavenCentral --no-configuration-cache + run: ./gradlew :signaturepad:publishToMavenCentral --no-configuration-cache if: success() env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} diff --git a/build.gradle.kts b/build.gradle.kts index 09c3180..ee8be74 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,7 @@ import com.vanniktech.maven.publish.MavenPublishBaseExtension +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension plugins { alias(libs.plugins.kotlin.multiplatform) apply false @@ -13,6 +16,12 @@ tasks.wrapper { gradleVersion = "9.5.1" } +// kotlin-js-store/yarn.lock resolves to slightly different contents across platforms (e.g. CI +// macOS vs a Linux dev machine), so don't fail the build on a mismatch — warn instead. +plugins.withType { + the().yarnLockMismatchReport = YarnLockMismatchReport.WARNING +} + allprojects { // Credentials must be added to ~/.gradle/gradle.properties per // https://vanniktech.github.io/gradle-maven-publish-plugin/central/#secrets diff --git a/signaturepad/build.gradle.kts b/signaturepad/build.gradle.kts index 5d3dc55..97cc0cc 100644 --- a/signaturepad/build.gradle.kts +++ b/signaturepad/build.gradle.kts @@ -1,6 +1,9 @@ -@file:OptIn(ExperimentalWasmDsl::class) +@file:OptIn(ExperimentalWasmDsl::class, KotlinNativeCacheApi::class) import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.plugin.mpp.DisableCacheInKotlinVersion +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCacheApi +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { alias(libs.plugins.android.kotlin.multiplatform.library) @@ -30,6 +33,18 @@ kotlin { iosArm64() iosSimulatorArm64() + // The Kotlin/Native compiler cache holds Compose ui-uikit objects that hard-reference newer + // UIKit symbols (e.g. UIViewLayoutRegion), which fail to link the iOS test binary. Disable the + // cache for the native targets so those symbols resolve correctly. + targets.withType().configureEach { + binaries.all { + disableNativeCache( + version = DisableCacheInKotlinVersion.`2_4_0`, + reason = "Compose ui-uikit cache references newer UIKit symbols that fail to link", + ) + } + } + explicitApi() jvmToolchain(17) diff --git a/signaturepad/src/jvmTest/kotlin/com/seanproctor/signaturepad/SignaturePadDrawingTest.kt b/signaturepad/src/jvmTest/kotlin/com/seanproctor/signaturepad/SignaturePadDrawingTest.kt index 2611687..113ed01 100644 --- a/signaturepad/src/jvmTest/kotlin/com/seanproctor/signaturepad/SignaturePadDrawingTest.kt +++ b/signaturepad/src/jvmTest/kotlin/com/seanproctor/signaturepad/SignaturePadDrawingTest.kt @@ -24,6 +24,7 @@ class SignaturePadDrawingTest { @Test fun clear_removesPreviouslyDrawnStrokes() { val state = SignaturePadStateImpl() + state.setSize(100, 100) // points outside the bounds are ignored, so give the pad a size state.gestureStarted(Offset(0f, 0f)) listOf(Offset(10f, 10f), Offset(20f, 0f), Offset(30f, 10f)).forEach { state.gestureMoved(it) } assertTrue(drawTo(state).drawnStrokes.isNotEmpty(), "precondition: signature has strokes") @@ -36,6 +37,7 @@ class SignaturePadDrawingTest { @Test fun gesture_needsFourPointsBeforeFirstCurve() { val state = SignaturePadStateImpl() + state.setSize(100, 100) // gestureStarted seeds two points; one move gives three — not enough for a cubic bezier. state.gestureStarted(Offset(0f, 0f)) state.gestureMoved(Offset(10f, 10f)) @@ -46,6 +48,7 @@ class SignaturePadDrawingTest { @Test fun gesture_producesOneCurvePerMoveAfterTheFirst() { val state = SignaturePadStateImpl() + state.setSize(100, 100) state.gestureStarted(Offset(0f, 0f)) // Well-separated points so each curve has a non-zero length and is actually drawn. val moves = listOf(Offset(10f, 10f), Offset(20f, 0f), Offset(30f, 10f), Offset(40f, 0f))