package net.keinekekse.version import io.github.z4kn4fein.semver.Version import io.github.z4kn4fein.semver.withoutSuffixes import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.* import java.util.* @CacheableTask abstract class AddVersionTask : DefaultTask() { // 1. Define what triggers the task (Source Files) @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) abstract val sourceFiles: ConfigurableFileCollection // 2. Define the output (The properties file) @get:OutputFile abstract val buildNumberFile: RegularFileProperty @get:OutputFile abstract val versionClassFile: RegularFileProperty @get:Input abstract val projectVersion: Property @get:Input abstract val projectName: Property @get:Input abstract val projectDescription: Property @get:Input abstract val displayNameExtra: Property @get:Input abstract val copyrightExtra: Property @get:Input abstract val versionPackageName: Property @get:Input abstract val modules: MapProperty> @TaskAction fun execute() { val buildNumber = incrementAndGetBuildNumber() writeClassFile(buildNumber) } private fun writeClassFile(buildNumber: String) { var fileContent = """ package ${versionPackageName.get()} import net.keinekekse.version.Version """.trimIndent() + buildVersionObject( "", projectVersion.get(), buildNumber, displayNameExtra.get(), copyrightExtra.get(), projectName.get(), projectDescription.get() ) if (modules.isPresent) { modules.get().forEach { (moduleName, moduleInfo) -> fileContent += buildVersionObject( moduleName, moduleInfo["version"] ?: "", buildNumber, moduleInfo["displayName"] ?: moduleName, moduleInfo["copyright"] ?: copyrightExtra.get(), moduleName, moduleInfo["description"] ?: "" ) } } val file = versionClassFile.get().asFile file.parentFile.mkdirs() file.writeText(fileContent) } private fun buildVersionObject( moduleName: String, versionString: String, buildNumber: String, longName: String, copy: String, shortName: String, desc: String, ): String { val ver = getVersionInfo(versionString, buildNumber, longName, copy, shortName, desc) val module = if (moduleName.isBlank()) { "" } else { "_$moduleName" } return """ object VERSION$module: Version { override val version = "${ver.version}" override val fullVersion = "${ver.fullVersion}" override val major = ${ver.major} override val minor = ${ver.minor} override val patch = ${ver.patch} override val preRelease = "${ver.preRelease}" override val buildMetadata = "${ver.buildMetadata}" override val buildDate = "${ver.buildDate}" override val displayName = "${ver.displayName}" override val copyright = "${ver.copyright}" override val name = "${ver.name}" override val description = "${ver.description}" } """.trimIndent() } private fun getVersionInfo( versionString: String, buildNumber: String, longName: String, copy: String, shortName: String, desc: String, ): VersionInfo { val version = if (Version.parse(versionString, strict = false).buildMetadata.isNullOrEmpty()) Version.parse("$versionString+build.$buildNumber", strict = false) else Version.parse(versionString, strict = false) println("Source files changed. Setting version to $version") return VersionInfo( major = version.major, minor = version.minor, patch = version.patch, preRelease = version.preRelease ?: "", buildMetadata = version.buildMetadata ?: "", fullVersion = version.toString(), version = if (version.isPreRelease) "${version.major}.${version.minor}.${version.patch}-${version.preRelease}" else version.withoutSuffixes().toString(), buildDate = java.time.Instant.now().toString(), displayName = longName, copyright = copy, name = shortName, description = desc ) } private fun incrementAndGetBuildNumber(): String { val file = buildNumberFile.get().asFile val props = Properties() if (file.exists()) { file.inputStream().use { props.load(it) } } val current = props.getProperty("build.number")?.toLongOrNull() ?: 0 val actual = (current + 1).toString() props.setProperty("build.number", actual) file.outputStream().use { props.store(it, "auto generated") } return actual } data class VersionInfo( val version: String, val fullVersion: String, val major: Int, val minor: Int, val patch: Int, val preRelease: String, val buildMetadata: String, val buildDate: String, val displayName: String, val copyright: String, val name: String, val description: String, ) }