diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a6b932f03..5e57cc0d9 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,11 +23,12 @@ repositories { } object Versions { - const val detekt = "1.20.0-RC1" + const val detekt = "1.20.0-RC2" const val dokka = "1.6.10" const val kotlin = "1.6.20" const val ktlintGradle = "10.2.1" const val pig = "0.6.1" + const val shadow = "8.1.1" } object Plugins { @@ -36,6 +37,7 @@ object Plugins { const val kotlinGradle = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}" const val ktlintGradle = "org.jlleitschuh.gradle:ktlint-gradle:${Versions.ktlintGradle}" const val pig = "org.partiql:pig-gradle-plugin:${Versions.pig}" + const val shadow = "com.github.johnrengelman:shadow:${Versions.shadow}" } dependencies { @@ -44,6 +46,7 @@ dependencies { implementation(Plugins.kotlinGradle) implementation(Plugins.ktlintGradle) implementation(Plugins.pig) + implementation(Plugins.shadow) } allprojects { diff --git a/buildSrc/src/main/kotlin/org/partiql/gradle/plugin/publish/PublishPlugin.kt b/buildSrc/src/main/kotlin/org/partiql/gradle/plugin/publish/PublishPlugin.kt index c7097f73a..f36e3c777 100644 --- a/buildSrc/src/main/kotlin/org/partiql/gradle/plugin/publish/PublishPlugin.kt +++ b/buildSrc/src/main/kotlin/org/partiql/gradle/plugin/publish/PublishPlugin.kt @@ -15,6 +15,8 @@ package org.partiql.gradle.plugin.publish +import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.plugins.JavaPlugin @@ -38,7 +40,7 @@ import java.io.File /** * Gradle plugin to consolidates the following publishing logic - * - Maven Publising + * - Maven Publishing * - Signing * - SourcesJar * - Dokka + JavadocJar @@ -51,6 +53,7 @@ abstract class PublishPlugin : Plugin { pluginManager.apply(MavenPublishPlugin::class.java) pluginManager.apply(SigningPlugin::class.java) pluginManager.apply(DokkaPlugin::class.java) + pluginManager.apply(ShadowPlugin::class.java) extensions.getByType(KotlinJvmProjectExtension::class.java).explicitApi = ExplicitApiMode.Strict val ext = extensions.create("publish", PublishExtension::class.java) target.afterEvaluate { publish(ext) } @@ -85,58 +88,98 @@ abstract class PublishPlugin : Plugin { from(tasks.named("dokkaHtml")) } + tasks.getByName("shadowJar") { + // Use the default name for published shadow jar + archiveClassifier.set("") + } + + tasks.getByName("jar") { + // Rename jar for `project` dependencies; not published to Maven + archiveClassifier.set("original") + } + // Setup Maven Central Publishing - val publishing = extensions.getByType(PublishingExtension::class.java).apply { - publications { - create("maven") { - artifactId = ext.artifactId - from(components["java"]) - pom { - packaging = "jar" - name.set(ext.name) - description.set(ext.description) - url.set(ext.url) - scm { - connection.set("scm:git@github.com:partiql/partiql-lang-kotlin.git") - developerConnection.set("scm:git@github.com:partiql/partiql-lang-kotlin.git") - url.set("git@github.com:partiql/partiql-lang-kotlin.git") - } - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + afterEvaluate { + val publishing = extensions.getByType(PublishingExtension::class.java).apply { + publications { + create("maven") { + // Publish the shadow jar; create dependencies separately since `ShadowExtension.component` + // does not include non-shadowed in POM dependencies + artifact(tasks["shadowJar"]) + artifact(tasks["sourcesJar"]) + artifact(tasks["javadocJar"]) + artifactId = ext.artifactId + pom { + packaging = "jar" + name.set(ext.name) + description.set(ext.description) + url.set(ext.url) + scm { + connection.set("scm:git@github.com:partiql/partiql-lang-kotlin.git") + developerConnection.set("scm:git@github.com:partiql/partiql-lang-kotlin.git") + url.set("git@github.com:partiql/partiql-lang-kotlin.git") } - } - developers { - developer { - name.set("PartiQL Team") - email.set("partiql-dev@amazon.com") - organization.set("PartiQL") - organizationUrl.set("https://github.com/partiql") + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + developers { + developer { + name.set("PartiQL Team") + email.set("partiql-dev@amazon.com") + organization.set("PartiQL") + organizationUrl.set("https://github.com/partiql") + } + } + // Publish the dependencies + withXml { + val dependenciesNode = asNode().appendNode("dependencies") + val apiDeps = project.configurations["api"].allDependencies + .filter { it.name !in ext.excludedDependencies } + val implDeps = project.configurations["implementation"].allDependencies + .filter { it !in apiDeps && it.name !in ext.excludedDependencies } + // Add Gradle 'api' dependencies; mapped to Maven 'compile' + apiDeps.forEach { dependency -> + val dependencyNode = dependenciesNode.appendNode("dependency") + dependencyNode.appendNode("groupId", dependency.group) + dependencyNode.appendNode("artifactId", dependency.name) + dependencyNode.appendNode("version", dependency.version) + dependencyNode.appendNode("scope", "compile") + } + // Add Gradle 'implementation' dependencies; mapped to Maven 'runtime' + implDeps.forEach { dependency -> + val dependencyNode = dependenciesNode.appendNode("dependency") + dependencyNode.appendNode("groupId", dependency.group) + dependencyNode.appendNode("artifactId", dependency.name) + dependencyNode.appendNode("version", dependency.version) + dependencyNode.appendNode("scope", "runtime") + } } } } } - } - repositories { - maven { - url = uri("https://aws.oss.sonatype.org/service/local/staging/deploy/maven2") - credentials { - val ossrhUsername: String by rootProject - val ossrhPassword: String by rootProject - username = ossrhUsername - password = ossrhPassword + repositories { + maven { + url = uri("https://aws.oss.sonatype.org/service/local/staging/deploy/maven2") + credentials { + val ossrhUsername: String by rootProject + val ossrhPassword: String by rootProject + username = ossrhUsername + password = ossrhPassword + } } } } - } - // Sign only if publishing to Maven Central - extensions.getByType(SigningExtension::class.java).run { - setRequired { - releaseVersion && gradle.taskGraph.allTasks.any { it is PublishToMavenRepository } + // Sign only if publishing to Maven Central + extensions.getByType(SigningExtension::class.java).run { + setRequired { + releaseVersion && gradle.taskGraph.allTasks.any { it is PublishToMavenRepository } + } + sign(publishing.publications["maven"]) } - sign(publishing.publications["maven"]) } } } @@ -146,6 +189,7 @@ abstract class PublishExtension { var name: String = "" var description: String = "" var url: String = "https://github.com/partiql/partiql-lang-kotlin" + var excludedDependencies: Set = setOf() override fun toString(): String { return "PublishExtension(artifactId='$artifactId', name='$name', description='$description', url='$url')" } diff --git a/buildSrc/src/main/kotlin/partiql.conventions.gradle.kts b/buildSrc/src/main/kotlin/partiql.conventions.gradle.kts index 7ac2a00ae..23cbad822 100644 --- a/buildSrc/src/main/kotlin/partiql.conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/partiql.conventions.gradle.kts @@ -55,7 +55,10 @@ java { tasks.test { useJUnitPlatform() // Enable JUnit5 - jvmArgs.addAll(listOf("-Duser.language=en", "-Duser.country=US")) + jvmArgs( + "-Duser.language=en", + "-Duser.country=US" + ) maxHeapSize = "4g" testLogging { events.add(TestLogEvent.FAILED) diff --git a/buildSrc/src/main/kotlin/partiql.versions.kt b/buildSrc/src/main/kotlin/partiql.versions.kt index 1d67f78c2..2fb76403b 100644 --- a/buildSrc/src/main/kotlin/partiql.versions.kt +++ b/buildSrc/src/main/kotlin/partiql.versions.kt @@ -52,7 +52,7 @@ object Versions { // Testing const val assertj = "3.11.0" - const val jacoco = "0.8.8" + const val jacoco = "0.8.11" const val junit5 = "5.9.3" const val junit5PlatformLauncher = "1.9.3" const val junit4 = "4.12" diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 4e4422669..749d49222 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -24,7 +24,6 @@ application { dependencies { implementation(project(":partiql-lang")) - implementation(project(":partiql-types")) implementation(Deps.kotlinxCoroutines) implementation(Deps.kotlinxCoroutinesJdk8) implementation(Deps.awsSdkS3) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f..7454180f2 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 98debb84d..48c0a02ca 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb6c..1b6c78733 100755 --- a/gradlew +++ b/gradlew @@ -205,12 +205,6 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 53a6b238d..ac1b06f93 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%"=="" @echo off +@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. +if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,15 +75,13 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd +if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/partiql-cli/build.gradle.kts b/partiql-cli/build.gradle.kts index e2ef41218..7dfc76632 100644 --- a/partiql-cli/build.gradle.kts +++ b/partiql-cli/build.gradle.kts @@ -20,13 +20,7 @@ plugins { dependencies { implementation(project(":partiql-lang")) - implementation(project(":partiql-ast")) - implementation(project(":partiql-parser")) - implementation(project(":partiql-plan")) - implementation(project(":partiql-planner")) - implementation(project(":partiql-types")) implementation(project(":plugins:partiql-local")) - implementation(project(":partiql-spi")) implementation(Deps.csv) implementation(Deps.awsSdkBom) implementation(Deps.awsSdkDynamodb) diff --git a/partiql-lang/build.gradle.kts b/partiql-lang/build.gradle.kts index d114530e9..1ef9cdac3 100644 --- a/partiql-lang/build.gradle.kts +++ b/partiql-lang/build.gradle.kts @@ -36,7 +36,7 @@ dependencies { api(Deps.ionElement) api(Deps.ionJava) api(Deps.ionSchema) - implementation(Deps.antlrRuntime) + shadow(Deps.antlrRuntime) implementation(Deps.csv) implementation(Deps.kotlinReflect) implementation(Deps.kotlinxCoroutines) @@ -64,6 +64,24 @@ dependencies { } } +val relocations = mapOf( + "org.antlr" to "org.partiql.lang.thirdparty.antlr" +) + +tasks.shadowJar { + configurations = listOf(project.configurations.shadow.get()) + for ((from, to) in relocations) { + relocate(from, to) + } +} + +// Workaround for https://github.com/johnrengelman/shadow/issues/651 +components.withType(AdhocComponentWithVariants::class.java).forEach { c -> + c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements.get()) { + skip() + } +} + publish { artifactId = "partiql-lang-kotlin" name = "PartiQL Lang Kotlin" diff --git a/partiql-parser/build.gradle.kts b/partiql-parser/build.gradle.kts index 24657d1e9..473936298 100644 --- a/partiql-parser/build.gradle.kts +++ b/partiql-parser/build.gradle.kts @@ -23,7 +23,26 @@ dependencies { api(project(":partiql-ast")) api(project(":partiql-types")) implementation(Deps.ionElement) - implementation(Deps.antlrRuntime) + shadow(Deps.antlrRuntime) +} + +val relocations = mapOf( + "org.antlr" to "org.partiql.parser.thirdparty.antlr" +) + +tasks.shadowJar { + dependsOn(tasks.named("generateGrammarSource")) + configurations = listOf(project.configurations.shadow.get()) + for ((from, to) in relocations) { + relocate(from, to) + } +} + +// Workaround for https://github.com/johnrengelman/shadow/issues/651 +components.withType(AdhocComponentWithVariants::class.java).forEach { c -> + c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements.get()) { + skip() + } } tasks.generateGrammarSource { @@ -42,8 +61,21 @@ tasks.compileKotlin { dependsOn(tasks.generateGrammarSource) } -tasks.findByName("sourcesJar")?.apply { - dependsOn(tasks.generateGrammarSource) +tasks.compileTestKotlin { + dependsOn(tasks.withType()) +} + +tasks.withType().configureEach { + // ensure "generateGrammarSource" is called before "sourcesJar". + dependsOn(tasks.withType()) +} + +tasks.withType().configureEach { + dependsOn(tasks.withType()) +} + +tasks.runKtlintCheckOverTestSourceSet { + dependsOn(tasks.withType()) } tasks.processResources { @@ -56,4 +88,9 @@ publish { artifactId = "partiql-parser" name = "PartiQL Parser" description = "PartiQL's experimental Parser" + // `antlr` dependency configuration adds the ANTLR API configuration (and Maven `compile` dependency scope on + // publish). It's a known issue w/ the ANTLR gradle plugin. Follow https://github.com/gradle/gradle/issues/820 + // for context. In the maven publishing step, any API or IMPLEMENTATION dependencies w/ "antlr4" non-runtime + // dependency will be omitted from the created Maven POM. + excludedDependencies = setOf("antlr4") } diff --git a/partiql-planner/build.gradle.kts b/partiql-planner/build.gradle.kts index f43b9a660..6a479fa08 100644 --- a/partiql-planner/build.gradle.kts +++ b/partiql-planner/build.gradle.kts @@ -112,14 +112,14 @@ tasks.register("copyUtils") { // // !! IMPORTANT !! — only run manually, as this will overwrite the existing ir/Nodes.kt. // -tasks.register("copyNodes") { - includeEmptyDirs = false - dependsOn("codegen") - filter { it.replace(Regex("public (?!(override|(fun visit)))"), "internal ") } - from("$buildDir/tmp") - include("**/Nodes.kt") - into("src/main/kotlin") -} +// tasks.register("copyNodes") { +// includeEmptyDirs = false +// dependsOn("codegen") +// filter { it.replace(Regex("public (?!(override|(fun visit)))"), "internal ") } +// from("$buildDir/tmp") +// include("**/Nodes.kt") +// into("src/main/kotlin") +// } tasks.register("generate") { dependsOn("codegen", "copyUtils") @@ -127,4 +127,31 @@ tasks.register("generate") { tasks.compileKotlin { dependsOn("generate") + dependsOn(tasks.withType()) +} + +tasks.withType().configureEach { + dependsOn(tasks.withType()) +} + +tasks.withType().configureEach { + dependsOn(tasks.withType()) +} + +tasks.withType().configureEach { + dependsOn(tasks.withType()) +} + +tasks.detekt { + dependsOn(tasks.withType()) +} + +tasks.withType().configureEach { + dependsOn(tasks.withType()) +} + +configure { + filter { + exclude { it.file.path.contains("Nodes.kt") } + } }