import java.util.Properties /** * Injects build-time secrets into `commonMain` so they stay out of version control. * * Each secret is read from the environment first (CI), then from `local.properties` * (local development), and defaults to an empty string when neither provides it — * consumers are expected to degrade gracefully rather than fail. * * The values are emitted as a generated `BuildSecrets` object, available to every * Kotlin target of the module. */ plugins { id("org.jetbrains.kotlin.multiplatform") } val secretsPackage = "bzh.ajaury.chombev" private val localProperties: Provider = providers .fileContents(layout.settingsDirectory.file("local.properties")) .asText .map { text -> Properties().apply { load(text.reader()) } } /** Resolves a secret from [environmentVariable], falling back to [localPropertyKey], then to an empty string. */ fun secret( environmentVariable: String, localPropertyKey: String, ): Provider = providers .environmentVariable(environmentVariable) .orElse(localProperties.map { properties -> properties.getProperty(localPropertyKey).orEmpty() }) .orElse("") // GlitchTip DSN, consumed by initializeSentry() in the shared module. val glitchtipDsn: Provider = secret(environmentVariable = "GLITCHTIP_DSN", localPropertyKey = "glitchtip.dsn") val generateBuildSecrets = tasks.register("generateBuildSecrets") { description = "Generates the BuildSecrets object from local.properties and environment variables." // Escaped here so the value can be inlined as-is in a Kotlin string literal. val dsn = glitchtipDsn.map { value -> value .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("$", "\${'$'}") } val outputDir = layout.buildDirectory.dir("generated/secrets/commonMain/kotlin") // Kept in locals so the execution-time action never captures the script instance. val packageName = secretsPackage val packagePath = packageName.replace('.', '/') inputs.property("glitchtipDsn", dsn) outputs.dir(outputDir) doLast { val file = outputDir .get() .asFile .resolve("$packagePath/BuildSecrets.kt") file.parentFile.mkdirs() file.writeText( """ package $packageName // Generated by the `gwenedeg.secrets` convention plugin. Do not edit. internal object BuildSecrets { const val GLITCHTIP_DSN: String = "${dsn.get()}" } """.trimIndent(), ) } } kotlin { sourceSets.commonMain { kotlin.srcDir(generateBuildSecrets) } }