app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 5d73568ffb852dea9749c23a75816d5adb932831
parent e9f598dd293e01d92e3ac5b8be39de33c18082fa
Author: triesap <tyson@radroots.org>
Date:   Mon, 10 Aug 2026 01:44:33 +0000

build: establish the KMP shared and desktop boundary

- add a one-target Kotlin Multiplatform shared module named desktop
- retain the JVM 21 desktop host and consume shared code as a project dependency
- move neutral recovery state and tests into common source sets
- verify discovery, compilation, lint, tests, and checks in both build lanes

Diffstat:
MMakefile | 10+++++-----
Mapp/desktop/build.gradle.kts | 1+
Dapp/desktop/src/main/kotlin/org/harvestcircle/application/GeneratedKeyBackup.kt | 19-------------------
Aapp/shared/build.gradle.kts | 36++++++++++++++++++++++++++++++++++++
Aapp/shared/src/commonMain/kotlin/org/harvestcircle/application/GeneratedKeyBackup.kt | 19+++++++++++++++++++
Rapp/desktop/src/test/kotlin/org/harvestcircle/application/GeneratedKeyBackupTest.kt -> app/shared/src/commonTest/kotlin/org/harvestcircle/application/GeneratedKeyBackupTest.kt | 0
Mbuild.gradle.kts | 1+
Mgradle/libs.versions.toml | 1+
Mgradle/verification-metadata.xml | 11+++++++++++
Msettings.gradle.kts | 2+-
10 files changed, 75 insertions(+), 25 deletions(-)

diff --git a/Makefile b/Makefile @@ -24,22 +24,22 @@ metadata: doctor format: doctor $(EXTBUILD) $(CARGO) fmt --manifest-path $(CARGO_MANIFEST) --all -- --check - $(EXTBUILD) $(GRADLE) --no-daemon :app:desktop:ktlintCheck + $(EXTBUILD) $(GRADLE) --no-daemon :app:shared:ktlintCheck :app:desktop:ktlintCheck format-fix: doctor $(EXTBUILD) $(CARGO) fmt --manifest-path $(CARGO_MANIFEST) --all - $(EXTBUILD) $(GRADLE) --no-daemon :app:desktop:ktlintFormat + $(EXTBUILD) $(GRADLE) --no-daemon :app:shared:ktlintFormat :app:desktop:ktlintFormat lint: doctor $(EXTBUILD) $(CARGO) clippy --manifest-path $(CARGO_MANIFEST) --workspace --all-targets --locked -- -D warnings - $(EXTBUILD) $(GRADLE) --no-daemon :app:desktop:detekt + $(EXTBUILD) $(GRADLE) --no-daemon :app:shared:detektCommonMainSourceSet :app:shared:detektCommonTestSourceSet :app:desktop:detekt test: doctor $(EXTBUILD) $(CARGO) test --manifest-path $(CARGO_MANIFEST) --workspace --locked - $(EXTBUILD) $(GRADLE) --no-daemon :app:desktop:test + $(EXTBUILD) $(GRADLE) --no-daemon :app:shared:desktopTest :app:desktop:test check: format lint test - $(EXTBUILD) $(GRADLE) --no-daemon :app:desktop:check + $(EXTBUILD) $(GRADLE) --no-daemon :app:shared:check :app:desktop:check build: doctor $(EXTBUILD) $(CARGO) build --manifest-path $(CARGO_MANIFEST) --workspace --locked diff --git a/app/desktop/build.gradle.kts b/app/desktop/build.gradle.kts @@ -612,6 +612,7 @@ abstract class VerifyMacOsNotarization : DefaultTask() { } dependencies { + implementation(projects.app.shared) implementation(compose.desktop.currentOs) implementation(libs.compose.foundation) implementation(libs.jna) diff --git a/app/desktop/src/main/kotlin/org/harvestcircle/application/GeneratedKeyBackup.kt b/app/desktop/src/main/kotlin/org/harvestcircle/application/GeneratedKeyBackup.kt @@ -1,19 +0,0 @@ -package org.harvestcircle.application - -class GeneratedKeyBackup internal constructor( - val npub: String, - nsec: String, -) { - private var recoveryText: String? = nsec - - internal fun revealNsec(): String = - checkNotNull(recoveryText) { - "Generated recovery material is no longer available" - } - - internal fun clear() { - recoveryText = null - } - - override fun toString(): String = "GeneratedKeyBackup(npub=$npub, nsec=[REDACTED])" -} diff --git a/app/shared/build.gradle.kts b/app/shared/build.gradle.kts @@ -0,0 +1,36 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType + +plugins { + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.detekt) + alias(libs.plugins.ktlint) +} + +providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull?.let { extBuildGradleRoot -> + layout.buildDirectory.set(file(extBuildGradleRoot).resolve("app-shared")) +} + +kotlin { + jvm("desktop") { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } + } + + sourceSets { + commonTest.dependencies { + implementation(kotlin("test")) + } + } + + jvmToolchain(21) + + check( + targets + .filter { it.platformType != KotlinPlatformType.common } + .map { it.name } == listOf("desktop"), + ) { + "HarvestCircle shared must declare exactly one KMP platform target named desktop" + } +} diff --git a/app/shared/src/commonMain/kotlin/org/harvestcircle/application/GeneratedKeyBackup.kt b/app/shared/src/commonMain/kotlin/org/harvestcircle/application/GeneratedKeyBackup.kt @@ -0,0 +1,19 @@ +package org.harvestcircle.application + +class GeneratedKeyBackup( + val npub: String, + nsec: String, +) { + private var recoveryText: String? = nsec + + fun revealNsec(): String = + checkNotNull(recoveryText) { + "Generated recovery material is no longer available" + } + + fun clear() { + recoveryText = null + } + + override fun toString(): String = "GeneratedKeyBackup(npub=$npub, nsec=[REDACTED])" +} diff --git a/app/desktop/src/test/kotlin/org/harvestcircle/application/GeneratedKeyBackupTest.kt b/app/shared/src/commonTest/kotlin/org/harvestcircle/application/GeneratedKeyBackupTest.kt diff --git a/build.gradle.kts b/build.gradle.kts @@ -1,6 +1,7 @@ import org.harvestcircle.gradle.VerifyProductCoordinates plugins { + alias(libs.plugins.kotlin.multiplatform) apply false alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.compose.multiplatform) apply false alias(libs.plugins.compose.compiler) apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } [plugins] +kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "compose" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml @@ -2616,6 +2616,9 @@ </artifact> </component> <component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="2.4.10"> + <artifact name="kotlin-stdlib-2.4.10-all.jar"> + <sha256 value="d0e49d626d43c6677c9ddb9396e88b48afee4b21b4082b0fb71d894b2fa06c0f" origin="Generated by Gradle"/> + </artifact> <artifact name="kotlin-stdlib-2.4.10.jar"> <sha256 value="4ec0293bc3751423b203f1d8493251c57c42e73eb6377a6b8560d0974ff0a6df" origin="Generated by Gradle"/> </artifact> @@ -2666,6 +2669,9 @@ </artifact> </component> <component group="org.jetbrains.kotlin" name="kotlin-test" version="2.4.10"> + <artifact name="kotlin-test-2.4.10-all.jar"> + <sha256 value="5760d52ee7696419c0fd9f73aebb3867bc862cca716ed920b470b27767cbc784" origin="Generated by Gradle"/> + </artifact> <artifact name="kotlin-test-2.4.10.jar"> <sha256 value="5d334a7b17ce9b223e4db35e355f0082fb0551d36c0424a599bf35686ba2ab7b" origin="Generated by Gradle"/> </artifact> @@ -2750,6 +2756,11 @@ <sha256 value="5b762d1fbe93d3cd5c8cdb8548dd9593dbc41e0d6d9d9dff36c9252678226992" origin="Generated by Gradle"/> </artifact> </component> + <component group="org.jetbrains.kotlin.multiplatform" name="org.jetbrains.kotlin.multiplatform.gradle.plugin" version="2.4.10"> + <artifact name="org.jetbrains.kotlin.multiplatform.gradle.plugin-2.4.10.pom"> + <sha256 value="2045cd0178f1d3b7046e83cdf4a0bda5180b76b3bcc2b0f929d7fc50a12eaf55" origin="Generated by Gradle"/> + </artifact> + </component> <component group="org.jetbrains.kotlin.plugin.compose" name="org.jetbrains.kotlin.plugin.compose.gradle.plugin" version="2.4.10"> <artifact name="org.jetbrains.kotlin.plugin.compose.gradle.plugin-2.4.10.pom"> <sha256 value="0c101ab316081659050fe9c0144b1b4bf725ebf9aa9943113bc221e923473d04" origin="Generated by Gradle"/> diff --git a/settings.gradle.kts b/settings.gradle.kts @@ -41,4 +41,4 @@ rootProject.name = "harvestcircle" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -include(":app:desktop") +include(":app:desktop", ":app:shared")