import se.bjurr.gitchangelog.plugin.gradle.GitChangelogTask import com.nwalsh.gradle.saxon.SaxonXsltTask buildscript { dependencies { classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: '12.5' } } plugins { id 'java' id 'maven-publish' id 'signing' id "org.javacc.javacc" version "latest.release" id 'jacoco' id 'com.github.kt3k.coveralls' version "latest.release" id "com.github.spotbugs" version "latest.release" id "com.diffplug.spotless" version "latest.release" id 'pmd' id 'checkstyle' id 'eclipse' // download the RR tools which have no Maven Repository id "de.undercouch.download" version "latest.release" id 'org.hidetake.ssh' version "latest.release" id "se.bjurr.gitchangelog.git-changelog-gradle-plugin" version "latest.release" id "me.champeau.jmh" version "latest.release" id "com.nwalsh.gradle.saxon.saxon-gradle" version "latest.release" id 'biz.aQute.bnd.builder' version "latest.release" } def getVersion = { boolean considerSnapshot -> Integer major = 0 Integer minor = 0 Integer patch = null Integer build = null String commit = null String snapshot = "" def versionStr = providers.exec { commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" }.standardOutput.asText.get().trim() def pattern = /(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ def matcher = versionStr =~ pattern if (matcher.find()) { major = matcher.group('major') as Integer ?: 0 minor = matcher.group('minor') as Integer ?: 0 patch = matcher.group('patch') as Integer ?: null build = matcher.group('build') as Integer ?: null commit = matcher.group('commit') ?: null } if (considerSnapshot && (versionStr.endsWith('SNAPSHOT') || build != null)) { minor++ if (patch != null) patch = 0 snapshot = "-SNAPSHOT" } return patch != null ? "${major}.${minor}.${patch}${snapshot}" : "${major}.${minor}${snapshot}" } // for publishing a release, call Gradle with Environment Variable RELEASE: // RELEASE=true gradle JSQLParser:publish version = getVersion( !System.getenv("RELEASE") ) group = 'com.github.jsqlparser' description = 'JSQLParser library' repositories { gradlePluginPortal() mavenLocal() mavenCentral() // Sonatype OSSRH maven { url = uri('https://s01.oss.sonatype.org/content/repositories/snapshots/') } maven { url "https://dev.saxonica.com/maven" } } configurations { xmlDoclet } dependencies { testImplementation 'commons-io:commons-io:2.+' testImplementation 'org.apache.commons:commons-text:+' testImplementation 'org.mockito:mockito-core:+' testImplementation 'org.assertj:assertj-core:+' testImplementation 'org.hamcrest:hamcrest-core:+' testImplementation 'org.apache.commons:commons-lang3:+' testImplementation 'com.h2database:h2:+' // for JaCoCo Reports testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.4' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4' // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter testImplementation 'org.mockito:mockito-junit-jupiter:+' // Performance Benchmark testImplementation 'org.openjdk.jmh:jmh-core:+' testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:+' // Java Doc in XML Format xmlDoclet 'com.manticore-projects.tools:xml-doclet:+' // enforce latest version of JavaCC testImplementation 'net.java.dev.javacc:javacc:+' javacc 'net.java.dev.javacc:javacc:+' } compileJavacc { arguments = [grammar_encoding: 'UTF-8', static: 'false', java_template_type: 'modern'] } java { withSourcesJar() withJavadocJar() sourceCompatibility = '11' targetCompatibility = '11' // needed for XML-Doclet to work (since Doclet changed again with Java 13) toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } javadoc { include("build/generated/javacc/net/sf/jsqlparser/parser/*.java" ) if(JavaVersion.current().isJava9Compatible()) { options.addBooleanOption('html5', true) } options.addBooleanOption("Xdoclint:none", true) } jar { manifest { attributes ( "Automatic-Module-Name": "net.sf.jsqlparser" ) } bundle { properties.empty() bnd( "Created-By": System.properties.get('user.name'), "Bundle-SymbolicName": "net.sf.jsqlparser", "Import-Package": "*", "Export-Package": "net.sf.jsqlparser.*", "Automatic-Module-Name": "net.sf.jsqlparser" ) } } tasks.register('xmldoc', Javadoc) { def outFile = reporting.file( version.endsWith("-SNAPSHOT") ? "xmlDoclet/javadoc_snapshot.xml" : "xmlDoclet/javadoc_stable.xml" ) def rstFile = reporting.file( version.endsWith("-SNAPSHOT") ? "xmlDoclet/javadoc_snapshot.rst" : "xmlDoclet/javadoc_stable.rst" ) source = sourceSets.main.allJava include("**/javacc/net/sf/jsqlparser/parser/*.java" ) destinationDir = reporting.file("xmlDoclet") options.docletpath = configurations.xmlDoclet.files as List options.doclet = "com.manticore.tools.xmldoclet.XmlDoclet" title = "API $version" options.addBooleanOption("rst", true) options.addBooleanOption("withFloatingToc", Boolean.parseBoolean(System.getenv().getOrDefault("FLOATING_TOC", "true"))) options.addStringOption("basePackage", "net.sf.jsqlparser") options.addStringOption("filename", outFile.getName()) dependsOn(compileJava) doLast { copy { from rstFile into "${projectDir}/src/site/sphinx/" } } } test { environment = [ 'EXPORT_TEST_TO_FILE': 'False' ] useJUnitPlatform() // set heap size for the test JVM(s) minHeapSize = "1G" maxHeapSize = "4G" // set JVM stack size jvmArgs = ['-Xss2m', '--add-opens=java.base/java.lang=ALL-UNNAMED'] jacoco { excludes = ['net/sf/jsqlparser/parser/CCJSqlParserTokenManager'] } } coveralls { jacocoReportPath 'build/reports/jacoco/test/jacocoTestReport.xml' } jacocoTestReport { dependsOn test // tests are required to run before generating the report reports { xml.required = false csv.required = false html.outputLocation = layout.buildDirectory.dir('reports/jacoco') } } jacocoTestCoverageVerification { // Jacoco can't handle the TokenManager class afterEvaluate { classDirectories.setFrom(files(classDirectories.files.collect { fileTree(dir: it, exclude: [ "**CCJSqlParserTokenManager**" ]) })) } violationRules { rule { //element = 'CLASS' limit { //@todo: temporarily reduced it 80%, we need to bring that back to 84% accepting the Keywords PR minimum = 0.50 } excludes = [ 'net.sf.jsqlparser.util.validation.*', 'net.sf.jsqlparser.**.*Adapter', 'net.sf.jsqlparser.parser.**' ] } rule { //element = 'CLASS' limit { counter = 'LINE' value = 'MISSEDCOUNT' //@todo: temporarily increased to 7000, we need to bring that down to 5500 after accepting the Keywords PR maximum = 20000 } excludes = [ 'net.sf.jsqlparser.util.validation.*', 'net.sf.jsqlparser.**.*Adapter', 'net.sf.jsqlparser.parser.**' ] } // rule { // element = 'CLASS' // limit { // counter = 'LINE' // value = 'MISSEDRATIO' // maximum = 0.3 // } // excludes = [ // 'net.sf.jsqlparser.util.validation.*', // 'net.sf.jsqlparser.**.*Adapter', // 'net.sf.jsqlparser.parser.**' // ] // } } } spotbugsMain { reports { html.required.set(true) html.outputLocation.set( layout.buildDirectory.file("reports/spotbugs/main/spotbugs.html").get().asFile ) html.stylesheet="fancy-hist.xsl" } } spotbugs { // fail only on P1 and without the net.sf.jsqlparser.parser.* excludeFilter = file("config/spotbugs/spotBugsExcludeFilter.xml") // do not run over the test, although we should do that eventually spotbugsTest.enabled = false } pmd { consoleOutput = true sourceSets = [sourceSets.main] // clear the ruleset in order to use configured rules only ruleSets = [] //rulesMinimumPriority = 1 ruleSetFiles = files("config/pmd/ruleset.xml") pmdMain { excludes = [ "build/generated/*" ] } } checkstyle { sourceSets = [sourceSets.main, sourceSets.test] configFile = rootProject.file('config/checkstyle/checkstyle.xml') } spotless { // optional: limit format enforcement to just the files changed by this feature branch ratchetFrom 'origin/master' format 'misc', { // define the files to apply `misc` to target '*.rst', '*.md', '.gitignore' // define the steps to apply to those files trimTrailingWhitespace() leadingTabsToSpaces(4) endWithNewline() } java { leadingTabsToSpaces(4) eclipse().configFile('config/formatter/eclipse-java-google-style.xml') } } tasks.withType(Checkstyle).configureEach { reports { xml.required = false html.required = true } excludes = [ "**/module-info.java" ] } tasks.register('renderRR') { dependsOn(compileJavacc) doLast { def rrDir = layout.buildDirectory.dir("rr").get().asFile // Download convert.war download.run { src 'http://manticore-projects.com/download/convert.war' dest new File(rrDir, "convert.war") overwrite false onlyIfModified true } // Download rr.war download.run { src 'http://manticore-projects.com/download/rr.war' dest new File(rrDir, "rr.war") overwrite false onlyIfModified true tempAndMove true } // Convert JJ file to EBNF tasks.register("convertJJ", JavaExec) { standardOutput = new FileOutputStream(new File(rrDir, "JSqlParserCC.ebnf")) mainClass = "-jar" args = [ new File(rrDir, "convert.war").absolutePath, layout.buildDirectory.dir("generated/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jj").get().asFile.absolutePath ] }.get().exec() // Generate RR diagrams tasks.register("generateRR", JavaExec) { mainClass = "-jar" args = [ new File(rrDir, "rr.war").absolutePath, "-noepsilon", "-color:#4D88FF", "-offset:0", "-width:800", "-out:${new File(rrDir, "JSqlParserCC.xhtml")}", new File(rrDir, "JSqlParserCC.ebnf").absolutePath ] }.get().exec() } } tasks.register('gitChangelogTask', GitChangelogTask) { fromRepo.set( file("$projectDir").toString() ) file.set( new File("${projectDir}/src/site/sphinx/changelog.rst") ) fromRevision.set( "4.0") //toRef = "1.1"; // switch off the formatter since the indentation matters for Mark-down // @formatter:off templateContent.set (""" ************************ Changelog ************************ {{#tags}} {{#ifMatches name "^Unreleased.*"}} Latest Changes since |JSQLPARSER_VERSION| {{/ifMatches}} {{#ifMatches name "^(?!Unreleased).*"}} Version {{name}} {{/ifMatches}} ============================================================= {{#issues}} {{#commits}} {{#ifMatches messageTitle "^(?!Merge).*"}} * **{{{messageTitle}}}** {{authorName}}, {{commitDate}} {{/ifMatches}} {{/commits}} {{/issues}} {{/tags}} """) // @formatter:on } tasks.register('updateKeywords', JavaExec) { group = "Execution" description = "Run the main class with JavaExecTask" classpath = sourceSets.main.runtimeClasspath args = [ file('src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt').absolutePath , file('src/site/sphinx/keywords.rst').absolutePath ] main("net.sf.jsqlparser.parser.ParserKeywordsUtils") dependsOn(compileJava) } task xslt(type: SaxonXsltTask) { def outFile = version.endsWith("-SNAPSHOT") ? file("src/site/sphinx/syntax_snapshot.rst") : file("src/site/sphinx/syntax_stable.rst") dependsOn(renderRR) stylesheet file('src/main/resources/rr/xhtml2rst.xsl') parameters ( "withFloatingToc": System.getenv().getOrDefault("FLOATING_TOC", "true"), "isSnapshot": Boolean.toString(version.endsWith("-SNAPSHOT")) ) // Transform every .xml file in the "input" directory. input layout.buildDirectory.file("rr/JSqlParserCC.xhtml").get() output outFile } tasks.register('sphinx', Exec) { dependsOn(gitChangelogTask, renderRR, xslt, xmldoc) String PROLOG = """ .. |_| unicode:: U+00A0 :trim: .. |JSQLPARSER_EMAIL| replace:: support@manticore-projects.com .. |JSQLPARSER_VERSION| replace:: ${getVersion(false)} .. |JSQLPARSER_SNAPSHOT_VERSION| replace:: ${getVersion(true)} .. |JSQLPARSER_STABLE_VERSION_LINK| raw:: html ${project.name}-${getVersion(false)}.jar .. |JSQLPARSER_SNAPSHOT_VERSION_LINK| raw:: html ${project.name}-${getVersion(true)}.jar """ args = [ "-Dproject=JSQLParser" , "-Dcopyright=Tobias Warneke, 2022" , "-Dauthor=Tobias Warneke" , "-Drelease=${getVersion(false)}" , "-Drst_prolog=$PROLOG" , "${projectDir}/src/site/sphinx" , layout.buildDirectory.file("sphinx").get().asFile ] executable "sphinx-build" //store the output instead of printing to the console: standardOutput = new ByteArrayOutputStream() //extension method stopTomcat.output() can be used to obtain the output: ext.output = { return standardOutput.toString() } } publish { dependsOn(check, gitChangelogTask, renderRR, xslt, xmldoc) } publishing { publications { create("mavenJava", MavenPublication) { artifactId = 'jsqlparser' from components.java versionMapping { usage('java-api') { fromResolutionOf('runtimeClasspath') } usage('java-runtime') { fromResolutionResult() } } pom { name.set('JSQLParser library') description.set('Parse SQL Statements into Abstract Syntax Trees (AST)') url.set('https://github.com/JSQLParser/JSqlParser') licenses { license { name.set('GNU Library or Lesser General Public License (LGPL) V2.1') url.set('http://www.gnu.org/licenses/lgpl-2.1.html') } license { name.set('The Apache Software License, Version 2.0') url.set('http://www.apache.org/licenses/LICENSE-2.0.txt') } } developers { developer { id.set('twa') name.set('Tobias Warneke') email.set('t.warneke@gmx.net') } developer { id.set('are') name.set('Andreas Reichel') email.set('andreas@manticore-projects.com') } } scm { connection.set('scm:git:https://github.com/JSQLParser/JSqlParser.git') developerConnection.set('scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git') url.set('https://github.com/JSQLParser/JSqlParser.git') } } } } repositories { maven { name = "ossrh" def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" url(version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl) credentials { username = providers.environmentVariable("ossrhUsername").orNull password = providers.environmentVariable("ossrhPassword").orNull } } } } signing { //def signingKey = findProperty("signingKey") //def signingPassword = findProperty("signingPassword") //useInMemoryPgpKeys(signingKey, signingPassword) // don't sign SNAPSHOTS if (!version.endsWith('SNAPSHOT')) { sign publishing.publications.mavenJava } } tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } remotes { webServer { host = findProperty("${project.name}.host") ?: "defaultHost" // Provide default if not found user = findProperty("${project.name}.username") ?: "defaultUsername" // Provide default if not found identity = file("${System.getProperty('user.home')}/.ssh/id_rsa") } } tasks.register('upload') { doFirst { if (findProperty("${project.name}.host") == null) { println( """ Property \"${project.name}.host\' not found. Please define \"${project.name}.host\" in the Gradle configuration (e. g. \$HOME/.gradle/gradle.properties. """ ) } } doLast { ssh.run { session(remotes.webServer) { def versionStable = getVersion(false) execute "mkdir -p download/${project.name}-${versionStable}" for (File file: fileTree(include:['*.jar'], dir: layout.buildDirectory.dir("libs").get()).collect()) { put from: file, into: "download/${project.name}-${versionStable}" } } } } dependsOn(check, assemble, gitChangelogTask, renderRR, xslt, xmldoc) } check { dependsOn jacocoTestCoverageVerification }