Files
Radixor/build.gradle
Leo Galambos c18563617d feat: add release changelog generation and package distribution integration
feat: add custom release changelog generator based on release tag ranges and prefixed commit lines
build: include generated CHANGELOG.md in the distribution ZIP when present
ci: generate release changelog during release workflow and use it as the GitHub release body
ci: split release packaging so distZip is rebuilt after changelog generation
chore: keep changelog generation out of quality-gate and report publishing workflows
2026-04-16 17:42:22 +02:00

337 lines
8.9 KiB
Groovy

plugins {
id 'java'
id 'eclipse'
id 'application'
id 'maven-publish'
id 'signing'
id 'pmd'
id 'jacoco'
id 'info.solidsoft.pitest' version '1.19.0'
id 'me.champeau.jmh' version '0.7.2'
id 'org.owasp.dependencycheck' version '12.2.1'
id 'org.cyclonedx.bom' version '3.2.4'
id 'com.palantir.git-version' version '4.0.0'
}
group = 'org.egothor'
version = gitVersion(prefix:'release@')
def benchmarkReportsDirectory = layout.buildDirectory.dir('reports/jmh')
def sbomReportsDirectory = layout.buildDirectory.dir('reports/sbom')
def nvdApiKey = providers.gradleProperty('nvdApiKey')
.orElse(providers.environmentVariable('NVD_API_KEY'))
.orNull
def dependencyCheckSuppressionFile = rootProject.file('dependency-suppression.xml')
apply from: 'gradle/maven-pom.gradle'
configurations {
mockitoAgent
}
java {
withSourcesJar()
withJavadocJar()
}
tasks.withType(AbstractArchiveTask).configureEach {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
jacoco {
toolVersion = '0.8.14'
}
pmd {
consoleOutput = true
toolVersion = '7.20.0'
sourceSets = [sourceSets.main]
ruleSetFiles = files(rootProject.file(".ruleset"))
}
tasks.withType(JavaCompile).configureEach {
options.release = 21
}
dependencyLocking {
lockAllConfigurations()
lockMode = LockMode.STRICT
}
dependencies {
jmhImplementation sourceSets.main.output
testImplementation platform(libs.junit.bom)
testImplementation libs.junit.jupiter
testRuntimeOnly libs.junit.platform.launcher
testImplementation libs.mockito.core
testImplementation libs.mockito.junit.jupiter
mockitoAgent(libs.mockito.core) {
transitive = false
}
}
dependencyCheck {
failBuildOnCVSS = 7.0
failOnError = true
autoUpdate = true
formats = ['HTML', 'JSON']
outputDirectory = layout.buildDirectory.dir('reports/dependency-check').get().asFile.absolutePath
/*
* Keep the scan focused on actual Java dependency inputs used by this project.
* testRuntimeClasspath is included intentionally because the current external
* dependency surface is primarily test-scoped.
*/
scanConfigurations = ['runtimeClasspath', 'testRuntimeClasspath', 'mockitoAgent']
skipTestGroups = false
analyzers {
experimentalEnabled = false
centralEnabled = true
}
nvd {
apiKey = nvdApiKey
delay = nvdApiKey != null ? 3500 : 8000
validForHours = 4
}
if (dependencyCheckSuppressionFile.exists()) {
suppressionFile = dependencyCheckSuppressionFile.absolutePath
failBuildOnUnusedSuppressionRule = true
}
}
tasks.withType(Test).configureEach {
useJUnitPlatform()
doFirst {
jvmArgs "-javaagent:${configurations.mockitoAgent.singleFile}"
}
finalizedBy(tasks.named('jacocoTestReport'))
reports {
junitXml.required = true
html.required = true
}
}
tasks.withType(Pmd).configureEach {
reports {
xml.required = true
html.required = true
}
}
tasks.named('jacocoTestReport', JacocoReport) {
dependsOn(tasks.named('test'))
reports {
xml.required = true
csv.required = false
html.required = true
}
}
tasks.named('check') {
dependsOn(tasks.named('jacocoTestReport'))
// no-default, only on-demand: dependsOn(tasks.named('dependencyCheckAnalyze'))
}
allprojects {
tasks.matching { it.name == 'cyclonedxDirectBom' }.configureEach {
includeConfigs = ['runtimeClasspath', 'compileClasspath']
skipConfigs = ['testRuntimeClasspath', 'testCompileClasspath', 'jmh.*', 'mockitoAgent']
includeBomSerialNumber = true
includeLicenseText = false
includeMetadataResolution = true
includeBuildSystem = true
}
}
tasks.named('cyclonedxBom') {
includeBomSerialNumber = true
includeLicenseText = false
includeBuildSystem = true
jsonOutput.set(sbomReportsDirectory.map { it.file('radixor-sbom.json') })
xmlOutput.set(sbomReportsDirectory.map { it.file('radixor-sbom.xml') })
}
pitest {
pitestVersion = '1.22.1'
junit5PluginVersion = '1.2.3'
targetClasses = [
'org.egothor.stemmer.*',
'org.egothor.stemmer.trie.*'
]
targetTests = [
'org.egothor.stemmer.*Test',
'org.egothor.stemmer.trie.*Test'
]
excludedClasses = ['org.egothor.stemmer.Compile']
outputFormats = ['XML', 'HTML']
timestampedReports = false
exportLineCoverage = true
failWhenNoMutations = true
threads = Math.max(1, Runtime.runtime.availableProcessors().intdiv(2))
}
application {
mainClass = 'org.egothor.stemmer.Compile'
applicationName = 'radixor'
executableDir = 'bin'
}
distributions {
main {
distributionBaseName = 'radixor'
contents {
from('README.md') {
into ''
}
from('LICENSE') {
into ''
}
from('docs') {
into 'docs'
include 'quick-start.md'
include 'cli-compilation.md'
include 'dictionary-format.md'
include 'built-in-languages.md'
include 'programmatic-usage.md'
include 'architecture-and-reduction.md'
include 'quality-and-operations.md'
include 'benchmarking.md'
}
from(layout.buildDirectory.dir('generated/release-notes')) {
into ''
include 'CHANGELOG.md'
}
}
}
}
tasks.named('startScripts') {
applicationName = 'radixor'
}
tasks.named('distZip', Zip) {
archiveBaseName = 'radixor'
archiveClassifier = 'bin'
}
tasks.named('distTar') {
enabled = false
}
jmh {
jmhVersion = '1.37'
warmupIterations = 3
iterations = 5
fork = 1
benchmarkMode = ['avgt']
timeUnit = 'ns'
resultFormat = 'CSV'
resultsFile = benchmarkReportsDirectory.map { it.file('jmh-results.csv').asFile }.get()
humanOutputFile = benchmarkReportsDirectory.map { it.file('jmh-results.txt').asFile }.get()
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks.named('jmh') {
group = 'verification'
description = 'Runs JMH benchmarks for the Radixor algorithmic core and Snowball comparison suite.'
}
tasks.register('regressionArtifactGenerator', JavaExec) {
group = 'verification'
description = 'Generates deterministic compiled trie regression artifacts.'
classpath = sourceSets.test.runtimeClasspath
mainClass = 'org.egothor.stemmer.RegressionArtifactGenerator'
if (project.hasProperty('regressionInput')) {
args '--input', project.property('regressionInput').toString()
}
if (project.hasProperty('regressionOutput')) {
args '--output', project.property('regressionOutput').toString()
}
if (project.hasProperty('regressionStoreOriginal')) {
args '--store-original', project.property('regressionStoreOriginal').toString()
}
if (project.hasProperty('regressionReductionMode')) {
args '--reduction-mode', project.property('regressionReductionMode').toString()
}
}
tasks.register('printDependencyCheckNvdConfig') {
doLast {
System.out.println("NVD API key present: " + (nvdApiKey != null && !nvdApiKey.isBlank()))
}
}
tasks.named('dependencyCheckAnalyze') {
dependsOn(tasks.named('printDependencyCheckNvdConfig'))
}
javadoc {
failOnError = false
options.addStringOption('Xdoclint:all,-missing', '-quiet')
options.addBooleanOption('html5', true)
options.tags('apiNote:a:API Note:')
options.tags('implSpec:a:Implementation Requirements:')
options.tags('implNote:a:Implementation Note:')
options.tags('param')
options.tags('return')
options.tags('throws')
options.tags('since')
options.tags('version')
options.tags('serialData')
options.tags('factory')
options.tags('see')
options.use = true
options.author = true
options.version = true
options.windowTitle = 'Radixor - Egothor Stemmer'
options.docTitle = 'Radixor - Egothor Stemmer API'
source = sourceSets.main.allJava
}
apply from: 'gradle/snowball-benchmarks.gradle'
gradle.taskGraph.whenReady { taskGraph ->
def banner = """
\u001B[34m
8888888888 .d8888b. .d88888b. 88888888888 888 888 .d88888b. 8888888b.
888 d88P Y88b d88P" "Y88b 888 888 888 d88P" "Y88b 888 Y88b
888 888 888 888 888 888 888 888 888 888 888 888
8888888 888 888 888 888 8888888888 888 888 888 d88P
888 888 88888 888 888 888 888 888 888 888 8888888P"
888 888 888 888 888 888 888 888 888 888 888 T88b
888 Y88b d88P Y88b. .d88P 888 888 888 Y88b. .d88P 888 T88b
8888888888 "Y8888P88 "Y88888P" 888 888 888 "Y88888P" 888 T88b
\u001B[36m
Project : ${project.name}
Version : ${project.version}
\u001B[0m
"""
println banner
}