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
337 lines
8.9 KiB
Groovy
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
|
|
}
|