Reworked how the version properties file is read/written to better handle command line options, tests, etc.

This commit is contained in:
Erik C. Thauvin 2019-04-11 07:30:11 -07:00
parent 6f4d3c1501
commit ad2a7ae786
5 changed files with 145 additions and 72 deletions

View file

@ -63,4 +63,19 @@ open class SemverConfig {
var separatorKey = DEFAULT_SEPARATOR var separatorKey = DEFAULT_SEPARATOR
get() = "$keysPrefix$field" get() = "$keysPrefix$field"
var keysPrefix = DEFAULT_KEYS_PREFIX var keysPrefix = DEFAULT_KEYS_PREFIX
override fun toString(): String {
return "SemverConfig(" +
"properties='$properties', " +
"majorKey='$majorKey', " +
"minorKey='$minorKey', " +
"patchKey='$patchKey', " +
"preReleaseKey='$preReleaseKey', " +
"preReleasePrefixKey='$preReleasePrefixKey', " +
"buildMetaKey='$buildMetaKey', " +
"buildMetaPrefixKey='$buildMetaPrefixKey', " +
"separator='$separatorKey', " +
"keysPrefix='$keysPrefix')" +
")"
}
} }

View file

@ -36,8 +36,6 @@ import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import java.io.File import java.io.File
import java.io.FileInputStream
import java.util.Properties
class SemverPlugin : Plugin<Project> { class SemverPlugin : Plugin<Project> {
private val simpleName = SemverPlugin::class.simpleName private val simpleName = SemverPlugin::class.simpleName
@ -61,48 +59,39 @@ class SemverPlugin : Plugin<Project> {
private fun afterEvaluate(project: Project) { private fun afterEvaluate(project: Project) {
val propsFile = File(config.properties) val propsFile = File(config.properties)
if (project.version != "unspecified") { if (project.version != "unspecified") {
project.logger.warn( project.logger.warn(
"Please specify the version in ${propsFile.name} and remove it from ${project.buildFile.name}") "Please specify the version in ${propsFile.name} and remove it from ${project.buildFile.name}")
} }
propsFile.apply { propsFile.apply {
val isNew = !exists()
project.logger.info( project.logger.info(
"[$simpleName] Attempting to read properties from: `$absoluteFile`. [exists: ${exists()}, isFile: $isFile, canRead: ${canRead()}]") "[$simpleName] Attempting to read properties from: `$absoluteFile`. [exists: $isNew, isFile: $isFile, canRead: ${propsFile.canRead()}]")
var hasReqProps = false
if (canRead() && isFile) {
FileInputStream(this).reader().use { reader ->
Properties().apply {
load(reader)
val requiredProps = setOf(config.majorKey, config.minorKey, config.patchKey, val props = Utils.loadProperties(propsFile)
config.preReleaseKey, config.buildMetaKey) val requiredProps = setOf(config.majorKey, config.minorKey, config.patchKey, config.preReleaseKey,
hasReqProps = stringPropertyNames().containsAll(requiredProps) && config.buildMetaKey)
Utils.isNotSystemProperty(requiredProps) val hasReqProps = !isNew && props.stringPropertyNames().containsAll(requiredProps) &&
Utils.isNotSystemProperty(requiredProps)
version.major = Utils.loadProperty(this, config.majorKey, Version.DEFAULT_MAJOR) println(isNew)
version.minor = Utils.loadProperty(this, config.minorKey, Version.DEFAULT_MINOR) println(props.stringPropertyNames().containsAll(requiredProps))
version.patch = Utils.loadProperty(this, config.patchKey, Version.DEFAULT_PATCH) println(Utils.isNotSystemProperty(requiredProps))
version.preRelease = Utils.loadProperty(this, config.preReleaseKey, Version.DEFAULT_EMPTY)
version.preReleasePrefix =
getProperty(config.preReleasePrefixKey, Version.DEFAULT_PRERELEASE_PREFIX)
version.buildMeta = Utils.loadProperty(this, config.buildMetaKey, Version.DEFAULT_EMPTY)
version.buildMetaPrefix =
getProperty(config.buildMetaPrefixKey, Version.DEFAULT_BUILDMETA_PREFIX)
version.separator = getProperty(config.separatorKey, Version.DEFAULT_SEPARATOR)
project.tasks.withType(SemverIncrementBuildMetaTask::class.java) { Utils.loadVersion(config, version, props)
buildMeta = version.buildMeta
} project.tasks.withType(SemverIncrementBuildMetaTask::class.java) {
} buildMeta = version.buildMeta
}
} else if (exists()) {
throw GradleException("Unable to read version from: `$absoluteFile`")
} }
project.version = version.semver project.version = version.semver
project.logger.info("[$simpleName] Project version set to: ${project.version}") project.logger.info("[$simpleName] Project version set to: ${project.version}")
if (!hasReqProps || !isFile) { if (!hasReqProps || !isFile) {
// If first time running and there is no props file, and the required version properties are missing, project.logger.info("[$simpleName] Saving version properties to `${config.properties}`.")
// then version props would never have been saved before
Utils.saveProperties(config, version) Utils.saveProperties(config, version)
} }
} }

View file

@ -14,45 +14,94 @@ import java.util.Properties
* @since 1.0 * @since 1.0
*/ */
object Utils { object Utils {
fun File.canReadFile(): Boolean {
return canRead() && isFile
}
private fun Properties.put(key: String, value: String, isValidCondition: Boolean) {
if (isValidCondition) put(key, value)
}
fun isNotSystemProperty(keys: Set<String>): Boolean { fun isNotSystemProperty(keys: Set<String>): Boolean {
keys.forEach { keys.forEach {
if (!System.getProperties().containsKey(it)) return true if (System.getProperties().containsKey(it)) return false
} }
return false return true
}
fun loadProperties(file: File): Properties {
var isNew = false
val props = Properties()
file.apply {
if (!exists()) {
if (!createNewFile()) {
throw GradleException("Unable to create: `$absoluteFile`")
} else {
isNew = true
}
}
if (canReadFile()) {
FileInputStream(this).reader().use { reader ->
props.apply {
if (!isNew) {
load(reader)
}
}
}
} else {
throw GradleException("Unable to read version from: `$absoluteFile`")
}
}
return props
} }
fun loadProperty(props: Properties, key: String, default: String): String { fun loadProperty(props: Properties, key: String, default: String): String {
return System.getProperty(key, props.getProperty(key, default)) return System.getProperty(key, if (props.isNotEmpty()) props.getProperty(key, default) else default)
}
fun loadVersion(config: SemverConfig, version: Version, props: Properties) {
props.apply {
version.major = loadProperty(this, config.majorKey, Version.DEFAULT_MAJOR)
version.minor = loadProperty(this, config.minorKey, Version.DEFAULT_MINOR)
version.patch = loadProperty(this, config.patchKey, Version.DEFAULT_PATCH)
version.preRelease = loadProperty(this, config.preReleaseKey, Version.DEFAULT_EMPTY)
version.buildMeta = loadProperty(this, config.buildMetaKey, Version.DEFAULT_EMPTY)
if (!isEmpty) {
version.preReleasePrefix =
getProperty(config.preReleasePrefixKey, Version.DEFAULT_PRERELEASE_PREFIX)
version.buildMetaPrefix =
getProperty(config.buildMetaPrefixKey, Version.DEFAULT_BUILDMETA_PREFIX)
version.separator = getProperty(config.separatorKey, Version.DEFAULT_SEPARATOR)
}
}
} }
fun saveProperties(config: SemverConfig, version: Version) { fun saveProperties(config: SemverConfig, version: Version) {
val propsFile = File(config.properties) val propsFile = File(config.properties)
SortedProperties().apply { SortedProperties().apply {
propsFile.apply { propsFile.apply {
if (canRead() && isFile) { if (canReadFile()) {
FileInputStream(this).reader().use { load(it) } FileInputStream(this).reader().use { load(it) }
} } else {
}
put(config.majorKey, version.major)
put(config.minorKey, version.minor)
put(config.patchKey, version.patch)
put(config.preReleaseKey, version.preRelease)
put(config.buildMetaKey, version.buildMeta)
if (version.buildMetaPrefix != Version.DEFAULT_BUILDMETA_PREFIX ||
containsKey(config.buildMetaPrefixKey))
put(config.buildMetaPrefixKey, version.buildMetaPrefix)
if (version.preReleasePrefix != Version.DEFAULT_PRERELEASE_PREFIX ||
containsKey(config.preReleasePrefixKey))
put(config.preReleasePrefixKey, version.preReleasePrefix)
if (version.separator != Version.DEFAULT_SEPARATOR || containsKey(config.separatorKey))
put(config.separatorKey, version.separator)
propsFile.apply {
if (!exists()) {
// Need to create the file as canWrite() will not work unless the file exists
createNewFile() createNewFile()
} }
put(config.majorKey, version.major)
put(config.minorKey, version.minor)
put(config.patchKey, version.patch)
put(config.preReleaseKey, version.preRelease)
put(config.buildMetaKey, version.buildMeta)
put(config.buildMetaPrefixKey, version.buildMetaPrefix,
version.buildMetaPrefix != Version.DEFAULT_BUILDMETA_PREFIX ||
containsKey(config.buildMetaPrefixKey))
put(config.preReleasePrefixKey, version.preReleasePrefix,
version.preReleasePrefix != Version.DEFAULT_PRERELEASE_PREFIX ||
containsKey(config.preReleasePrefixKey))
put(config.separatorKey, version.separator,
version.separator != Version.DEFAULT_SEPARATOR ||
containsKey(config.separatorKey))
if (canWrite()) { if (canWrite()) {
FileOutputStream(this).writer().use { FileOutputStream(this).writer().use {
store(it, "Generated by the Semver Plugin for Gradle") store(it, "Generated by the Semver Plugin for Gradle")

View file

@ -68,4 +68,17 @@ class Version {
} }
if (isPatch) patch = (patch.toInt() + 1).toString() if (isPatch) patch = (patch.toInt() + 1).toString()
} }
override fun toString(): String {
return "Version(" +
"major='$major', " +
"minor='$minor', " +
"patch='$patch', " +
"preRelease='$preRelease', " +
"preReleasePrefix='$preReleasePrefix', " +
"buildMeta='$buildMeta', " +
"buildMetaPrefix='$buildMetaPrefix', " +
"separator='$separator'" +
")"
}
} }

View file

@ -31,10 +31,10 @@
*/ */
package net.thauvin.erik.gradle.semver package net.thauvin.erik.gradle.semver
import net.thauvin.erik.gradle.semver.Utils.canReadFile
import org.spekframework.spek2.Spek import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe import org.spekframework.spek2.style.specification.describe
import java.io.File import java.io.File
import java.nio.file.Files
import java.util.Properties import java.util.Properties
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNull import kotlin.test.assertNull
@ -43,30 +43,23 @@ import kotlin.test.assertTrue
@Suppress("unused") @Suppress("unused")
object UtilsSpec : Spek({ object UtilsSpec : Spek({
describe("a config and version") { describe("a config and version") {
val version by memoized { Version() } val version = Version()
val config by memoized { SemverConfig() } val config = SemverConfig()
val configFile = File("test.properties") val propsFile = File("test.properties")
lateinit var props: Properties lateinit var props: Properties
before {
config.properties = configFile.name
}
describe("save properties") { describe("save properties") {
it("should save properties") { it("save properties") {
config.properties = propsFile.name
Utils.saveProperties(config, version) Utils.saveProperties(config, version)
assertTrue(configFile.exists()) assertTrue(propsFile.canReadFile())
} }
it("load the properties") { it("load the properties") {
props = Properties().apply { props = Utils.loadProperties(propsFile)
Files.newInputStream(configFile.toPath()).use { nis -> propsFile.delete()
load(nis)
}
configFile.delete()
}
} }
} }
describe("validate the properties file") { describe("validate the properties") {
it("version should be the same") { it("version should be the same") {
assertEquals(props.getProperty(config.majorKey), version.major, "Major") assertEquals(props.getProperty(config.majorKey), version.major, "Major")
assertEquals(props.getProperty(config.minorKey), version.minor, "Minor") assertEquals(props.getProperty(config.minorKey), version.minor, "Minor")
@ -95,6 +88,20 @@ object UtilsSpec : Spek({
assertEquals(Utils.loadProperty(props, it.first, ""), it.second) assertEquals(Utils.loadProperty(props, it.first, ""), it.second)
} }
} }
it("load version") {
Utils.loadVersion(config, version, props)
assertEquals(version.semver, "2.1.1-beta+007")
}
it("save new properties") {
Utils.saveProperties(config, version)
}
it("check saved properties") {
val newProps = Utils.loadProperties(propsFile)
newVersion.forEach {
assertEquals(newProps.getProperty(it.first), it.second, it.second)
}
propsFile.delete()
}
} }
} }
}) })