Introduce new package org.egothor.methodatlas.ai providing AI-assisted classification of JUnit tests for security relevance. Key changes: - add AI suggestion engine, provider abstraction, and provider clients (OpenAI-compatible, Ollama, Anthropic) - implement strict JSON prompt/response contract and taxonomy handling - integrate AI enrichment into MethodAtlas CLI output (CSV and plain modes) - add configuration via AiOptions and CLI flags - add comprehensive JUnit + Mockito test coverage for AI components and CLI integration scenarios - add realistic test fixtures for security-related test classes - update Gradle configuration for Mockito agent support on JDK 21+ - provide complete Javadoc for the AI module The AI layer is optional and degrades gracefully when providers are unavailable or responses fail.
170 lines
4.5 KiB
Groovy
170 lines
4.5 KiB
Groovy
plugins {
|
|
id 'java'
|
|
id 'application'
|
|
id 'pmd'
|
|
id 'com.palantir.git-version' version '4.0.0'
|
|
}
|
|
|
|
group = 'org.egothor.methodatlas'
|
|
version = gitVersion(prefix:'release@')
|
|
|
|
configurations {
|
|
mockitoAgent
|
|
}
|
|
|
|
java {
|
|
toolchain {
|
|
languageVersion = JavaLanguageVersion.of(21)
|
|
}
|
|
}
|
|
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
|
|
dependencies {
|
|
implementation 'com.github.javaparser:javaparser-core:3.28.0'
|
|
implementation 'com.fasterxml.jackson.core:jackson-databind:2.21.1'
|
|
|
|
testImplementation(platform("org.junit:junit-bom:5.14.2"))
|
|
testImplementation 'org.junit.jupiter:junit-jupiter'
|
|
testImplementation 'org.mockito:mockito-core:5.22.0'
|
|
testImplementation 'org.mockito:mockito-junit-jupiter:5.22.0'
|
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
|
|
mockitoAgent('org.mockito:mockito-core:5.22.0') {
|
|
transitive = false
|
|
}
|
|
}
|
|
|
|
tasks.withType(Test).configureEach {
|
|
useJUnitPlatform()
|
|
jvmArgs "-javaagent:${configurations.mockitoAgent.singleFile}"
|
|
|
|
doFirst {
|
|
println "Mockito agent: ${configurations.mockitoAgent.singleFile}"
|
|
println "JVM args: ${jvmArgs}"
|
|
}
|
|
}
|
|
|
|
application {
|
|
mainClass = 'org.egothor.methodatlas.MethodAtlasApp'
|
|
}
|
|
|
|
tasks.test {
|
|
useJUnitPlatform()
|
|
}
|
|
|
|
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 = 'MethodAtlas'
|
|
options.docTitle = 'MethodAtlas API'
|
|
|
|
source = sourceSets.main.allJava
|
|
}
|
|
|
|
tasks.named('jar') {
|
|
enabled = false
|
|
}
|
|
|
|
tasks.register('fatJar', Jar) {
|
|
archiveClassifier = ''
|
|
manifest {
|
|
attributes(
|
|
'Main-Class': application.mainClass.get(),
|
|
'Implementation-Title': rootProject.name,
|
|
'Implementation-Version': "${version}"
|
|
)
|
|
}
|
|
|
|
from sourceSets.main.output
|
|
dependsOn configurations.runtimeClasspath
|
|
|
|
// Include each JAR dependency
|
|
configurations.runtimeClasspath.findAll { it.exists() && it.name.endsWith('.jar') }.each { jarFile ->
|
|
def jarName = jarFile.name.replaceAll(/\.jar$/, '')
|
|
|
|
from(zipTree(jarFile)) {
|
|
// Exclude signature-related files
|
|
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'
|
|
|
|
// Rename license/notice files to avoid conflicts
|
|
eachFile { file ->
|
|
if (file.path ==~ /META-INF\/(LICENSE|NOTICE)(\..*)?/) {
|
|
file.path = "META-INF/licenses-from-${jarName}/${file.name}"
|
|
}
|
|
}
|
|
|
|
includeEmptyDirs = false
|
|
}
|
|
}
|
|
|
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
}
|
|
|
|
distributions {
|
|
create('fat') {
|
|
distributionBaseName = project.name
|
|
contents {
|
|
into('bin') {
|
|
from(tasks.named('startScripts'))
|
|
filePermissions {
|
|
unix('rwxr-xr-x')
|
|
}
|
|
}
|
|
into('lib') {
|
|
from(tasks.named('fatJar'))
|
|
}
|
|
from('src/dist')
|
|
}
|
|
}
|
|
}
|
|
|
|
tasks.named('assemble') {
|
|
dependsOn tasks.named('fatDistZip'), tasks.named('fatDistTar')
|
|
}
|
|
|
|
tasks.named('startScripts') {
|
|
dependsOn tasks.named('fatJar')
|
|
classpath = files(tasks.named('fatJar').flatMap { it.archiveFile })
|
|
}
|
|
|
|
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
|
|
}
|