Versionsinfo in META-INF/MANIFEST.MF eintragen

This commit is contained in:
Hartmut Bauer committed 2025-03-12 00:22:03 +01:00
1 parent f5b99c3038
commit 0ec2193cc7
6 files changed
+116 -121

No files matched your search

+17 -12
View File
@@ -1,27 +1,32 @@
import java.time.Instant import java.time.Instant
/*
* This file was generated by the Gradle 'init' task.
*
* This is a general purpose Gradle build.
* To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.6/samples
*/
plugins { plugins {
`kotlin-dsl` `kotlin-dsl`
`maven-publish` `maven-publish`
} }
repositories { repositories {
mavenCentral() maven("https://nexus.keinekekse.net/repository/maven-public/")
} }
group = "net.keinekekse" group = "net.keinekekse"
version = libs.versions.versionplugin.get() version = masterLibs.versions.versionPluginVersion.get()
description = "Adds version information to the project." description = "Adds version information to the project."
project.ext.set("displayname", "Version-Plugin") extra["displayname"] = "Version-Plugin"
project.ext.set("copyright", "(c) 2024 Hartmut Bauer") extra["copyright"] = "Copyright (c) 2024-2025 Hartmut Bauer"
project.ext.set("buildTimestamp", Instant.now().toString()) extra["buildTimestamp"] = Instant.now().toString()
publishing {
repositories {
maven {
credentials {
username = "admin"
password = "admin123"
}
url = uri("https://nexus.keinekekse.net/repository/maven-releases/")
}
}
}
gradlePlugin { gradlePlugin {
plugins { plugins {
create("version-plugin") { create("version-plugin") {
@@ -33,6 +38,6 @@ gradlePlugin {
java { java {
toolchain { toolchain {
languageVersion.set(JavaLanguageVersion.of(17)) languageVersion.set(JavaLanguageVersion.of(masterLibs.versions.javaVersion.get()))
} }
} }
+1
View File
@@ -0,0 +1 @@
kotlin.code.style=official
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
+6 -9
View File
@@ -1,16 +1,13 @@
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.6/userguide/multi_project_builds.html in the Gradle documentation.
*/
rootProject.name = "version-plugin" rootProject.name = "version-plugin"
dependencyResolutionManagement { dependencyResolutionManagement {
repositories {
maven("https://nexus.keinekekse.net/repository/maven-public/")
}
versionCatalogs { versionCatalogs {
create("libs") { create("masterLibs") {
from(files("../../gradle-deps/libs.versions.toml")) from("net.keinekekse:version-catalog:56")
} }
} }
} }
@@ -3,127 +3,129 @@ package net.keinekekse.version
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFile
import org.gradle.api.java.archives.Manifest
import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.War import org.gradle.api.tasks.bundling.War
import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.named
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.OutputStreamWriter import java.time.Instant
import java.util.* import java.util.*
class VersionPlugin : Plugin<Project> { class VersionPlugin : Plugin<Project> {
private lateinit var versionFileName: String
private val buildNumProp = "buildNumber"
private val addTaskName = "addVersion"
private var isWar = false private var isWar = false
companion object {
private const val BUILDNUMBER_FILE = "buildnumber.properties"
private const val BUILD_NUMBER_KEY = "build.number"
private const val GENERATED_COMMENT = "auto generated"
}
override fun apply(project: Project) { override fun apply(project: Project) {
// println("Version Plugin") validateNoSubprojects(project)
val extension = project.extensions.create("version", VersionPluginExtension::class.java)
versionFileName = extension.propertiesFilename.orNull ?: "${project.name}.properties"
val warSource = project.afterEvaluate {
project.layout.projectDirectory.file("src/main/webapp/WEB-INF/classes/${versionFileName}") val projectInfo = ProjectInfo(
val jarSource = version = project.version.toString(),
project.layout.projectDirectory.file("src/main/properties/${versionFileName}") displayName = getOptionalExtra(project, "displayname"),
val targetDir = project.layout.buildDirectory.dir("resources/main") copyright = getOptionalExtra(project, "copyright"),
val countFile = project.layout.projectDirectory.file("buildnumber.properties") name = project.name,
if (warSource.asFile.parentFile.parentFile.exists()) { description = project.description ?: ""
isWar = true )
}
if (isWar) {
if (!warSource.asFile.parentFile.exists())
warSource.asFile.parentFile.mkdir()
checkVersionFile(warSource)
} else {
checkVersionFile(jarSource)
}
if (isWar) { isWar = isWarProject(project)
if (isWar) {
addManifestTask(project, "war", projectInfo)
} else {
addManifestTask(project, "jar", projectInfo)
}
}
}
private fun validateNoSubprojects(project: Project) {
if (project.parent != null) {
throw Exception("This plugin cannot handle subprojects!")
}
}
private fun isWarProject(project: Project): Boolean {
return project.layout.projectDirectory.file("src/main/webapp/WEB-INF").asFile.exists()
}
private fun getOptionalExtra(project: Project, key: String): String {
return try {
project.extra[key]?.toString() ?: ""
} catch (e: Exception) {
""
}
}
private fun addManifestTask(project: Project, taskType: String, projectInfo: ProjectInfo) {
val countFile = project.layout.projectDirectory.file(BUILDNUMBER_FILE)
if (taskType == "war") {
try { try {
project.tasks.named<War>("war") { project.tasks.named<War>(taskType) {
filesMatching("**/${versionFileName}") { doFirst {
val num = buildNumber(countFile) applyManifestAttributes(manifest, countFile, projectInfo)
project.extra[buildNumProp] = num
expand(project.properties)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
println("\n*** Falsche Reihenfolge ***\n\nWAR-Plugin muss vor dem Versions-Plugin eingetragen werden!\n") println("\n*** Falsche Reihenfolge ***\n\nwar-Plugin muss vor dem Versions-Plugin eingetragen werden!\n")
throw e throw e
} }
} else { } else if (taskType == "jar") {
project.tasks.named<Jar>("jar") { project.tasks.named<Jar>(taskType) {
dependsOn(project.tasks.named(addTaskName)) doFirst {
} applyManifestAttributes(manifest, countFile, projectInfo)
project.tasks.register(addTaskName, AddVersionTask::class.java) {
group = "net.keinekekse"
description = "Adds version information to the project."
outputs.upToDateWhen { false }
mustRunAfter(project.tasks.named("classes"))
onlyIf {
val cj by project.tasks.named("compileJava")
val pr by project.tasks.named("processResources")
// (cj.state.didWork || pr.didWork)
((cj.state.didWork && !cj.state.upToDate) || (pr.didWork && !pr.state.upToDate))
}
from(jarSource)
into(targetDir)
filesMatching("*") {
val num = buildNumber(countFile)
project.extra[buildNumProp] = num
expand(project.properties)
} }
} }
} }
} }
/** private fun applyManifestAttributes(
* Increment build number manifest: Manifest,
*/ countFile: RegularFile,
private fun buildNumber(propFile: RegularFile): String { projectInfo: ProjectInfo,
val propName = "build.number" ) {
val props = Properties() val buildNumber = incrementBuildNumber(countFile)
with(manifest.attributes) {
this["module-name"] = projectInfo.name
this["displayname"] = projectInfo.displayName
this["description"] = projectInfo.description
this["copyright"] = projectInfo.copyright
this["version"] = projectInfo.version
this["build-number"] = buildNumber
this["build-timestamp"] = Instant.now().toString()
}
println("build ${projectInfo.version}-$buildNumber")
}
private fun incrementBuildNumber(propFile: RegularFile): String {
val props = Properties()
try { try {
FileInputStream(propFile.asFile).use { props.load(it) } FileInputStream(propFile.asFile).use { props.load(it) }
} catch (e: Exception) { } catch (e: Exception) {
// noop // noop
} }
val numStr: String? = props.getProperty(propName)
var num = numStr?.toLongOrNull() ?: 0 val currentBuildNumber = props.getProperty(BUILD_NUMBER_KEY)?.toLongOrNull() ?: 0
num++ val newBuildNumber = currentBuildNumber + 1
println("build number ${num}")
props.setProperty(propName, num.toString()) props.setProperty(BUILD_NUMBER_KEY, newBuildNumber.toString())
props.store(FileOutputStream(propFile.asFile, false), "auto generated") props.store(FileOutputStream(propFile.asFile, false), GENERATED_COMMENT)
return num.toString()
return newBuildNumber.toString()
} }
/** data class ProjectInfo(
* Create version properties file if it doesn't exist val version: String,
*/ val displayName: String,
private fun checkVersionFile(file: RegularFile) { val copyright: String,
if (!file.asFile.exists()) { val name: String,
val content = """ val description: String,
|name=${'$'}{name} )
|displayname=${'$'}{displayname}
|description=${'$'}{description}
|copyright=${'$'}{copyright}
|version=${'$'}{version}
|build.number=${'$'}{${buildNumProp}}
|build.timestamp=${'$'}{buildTimestamp}
""".trimMargin()
val outfile = OutputStreamWriter(FileOutputStream(file.asFile))
outfile.write(content)
outfile.close()
}
}
} }
@@ -2,14 +2,4 @@ package net.keinekekse.version
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
interface VersionPluginExtension { interface VersionPluginExtension
/**
* Name for the version properties file
* (JAR: src/main/properties, WAR: src/main/webapp/WEB-INF/classes)
* Will be copied to the classpath root.
*
* Default: <project.name>.properties
*/
val propertiesFilename: Property<String>
}