[#31] Add injection of build info

Provides infrastructure to help us track exactly what build of the app is running.  This provides the ability to implement a number of features in the future
 - Displaying build version in an About screen
 - Automatically versioning with Git commit count as an incrementing version number
 - Injection of secrets, API keys, or other behaviors into the build so that the app can leverage them at runtime.  The secrets can be securely stored as environment variables (e.g. on CI), so they don't need to be committed to the repository.
This commit is contained in:
Carter Jernigan 2021-10-19 09:24:45 -04:00 committed by Carter Jernigan
parent c5f3a44340
commit f3c425e68a
6 changed files with 122 additions and 0 deletions

View File

@ -0,0 +1,78 @@
import java.text.SimpleDateFormat
import java.util.*
plugins {
kotlin("multiplatform")
id("zcash.kotlin-multiplatform-build-conventions")
}
// Injects build information
// Note timestamp is not currently injected because it effectively disables the cache since it
// changes with every build
val generateBuildConfigTask = tasks.create("buildConfig") {
val generatedDir = "$buildDir/generated"
val gitInfo = co.electriccoin.zcash.Git.newInfo(parent!!.projectDir)
//val buildTimestamp = newIso8601Timestamp()
inputs.property("gitSha", gitInfo.sha)
inputs.property("gitCommitCount", gitInfo.commitCount)
//inputs.property("buildTimestamp", buildTimestamp)
outputs.dir(File(generatedDir))
doLast {
val outputFile = File("$generatedDir/co/electriccoin/zcash/build/BuildConfig.kt")
outputFile.parentFile.mkdirs()
// To add timestamp, add this to the output below
// import kotlinx.datetime.Instant
// import kotlinx.datetime.toInstant
// val buildTimestamp: Instant = "$buildTimestamp".toInstant()
outputFile.writeText(
"""
// Generated file
package co.electriccoin.zcash.build
const val gitSha: String = "${gitInfo.sha}"
const val gitCommitCount: Int = ${gitInfo.commitCount}
""".trimIndent()
)
}
}
kotlin {
jvm()
sourceSets {
getByName("commonMain") {
dependencies {
kotlin.srcDir(generateBuildConfigTask)
//api(libs.kotlinx.datetime)
}
}
getByName("commonTest") {
dependencies {
implementation(kotlin("test"))
}
}
getByName("jvmMain") {
dependencies {
}
}
getByName("jvmTest") {
dependencies {
implementation(kotlin("test"))
}
}
}
}
/**
* @return Current ISO 8601 timestamp.
*/
fun newIso8601Timestamp(): String {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ").apply {
timeZone = TimeZone.getTimeZone("UTC")
}
return formatter.format(Date())
}

19
buildSrc/build.gradle.kts Normal file
View File

@ -0,0 +1,19 @@
import org.jetbrains.kotlin.konan.properties.loadProperties
plugins {
`java-gradle-plugin`
`kotlin-dsl`
}
repositories {
mavenCentral()
}
dependencies {
val rootProperties = getRootProperties()
implementation("org.eclipse.jgit:org.eclipse.jgit:${rootProperties.getProperty("JGIT_VERSION")}")
}
// A slightly gross way to use the root gradle.properties as the single source of truth for version numbers
fun getRootProperties() = loadProperties(File(project.projectDir.parentFile, "gradle.properties").path)

View File

@ -0,0 +1,22 @@
package co.electriccoin.zcash
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.ObjectId
import java.io.File
object Git {
// Get the info for the current branch
private const val HEAD = "HEAD"
fun newInfo(workingDirectory: File): GitInfo {
val git = Git.open(workingDirectory)
val repository = git.repository
val head: ObjectId = repository.resolve(HEAD)
val count = git.log().call().count()
return GitInfo(ObjectId.toString(head), count)
}
}
data class GitInfo(val sha: String, val commitCount: Int)

View File

@ -23,6 +23,7 @@ The main entrypoints of the application are:
The logical components of the app are implemented as a number of Gradle modules.
* app — Compiles all of the modules together into the final application. This module contains minimal actual code. Note that the Java package structure for this module is under `cash.z.ecc.app` while the Android package name is `cash.z.ecc`.
* build-info-lib — Collects information from the build environment (e.g. Git SHA, Git commit count) and compiles them into the application. Can also be used for injection of API keys or other secrets.
* ui-lib — User interface that the user interacts with. This contains 99% of the UI code, along with localizations, icons, and other assets.
* preference
* preference-api-lib — Multiplatform interfaces for key-value storage of preferences

View File

@ -49,6 +49,7 @@ ANDROID_GRADLE_PLUGIN_VERSION=7.0.3
DETEKT_VERSION=1.18.1
GRADLE_VERSIONS_PLUGIN_VERSION=0.38.0
KTLINT_VERSION=0.42.1
JGIT_VERSION=5.12.0.202106070339-r
ANDROIDX_ACTIVITY_VERSION=1.3.1
ANDROIDX_ANNOTATION_VERSION=1.2.0

View File

@ -121,6 +121,7 @@ rootProject.name = "zcash-android-app"
includeBuild("build-conventions")
include("app")
include("build-info-lib")
include("preference-api-lib")
include("preference-impl-android-lib")
include("test-lib")