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 testImplementation libs.jqwik 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 '**/*.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' options.overview = file('src/main/javadoc/overview.html') options.bottom = """