Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changes/0011f293-6d95-46ab-ac8c-59d11ef54559.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "0011f293-6d95-46ab-ac8c-59d11ef54559",
"type": "feature",
"description": "Enhance generic codegen to be more KMP-friendly. This is a **breaking change** which means service client artifacts will now include their platform name (e.g., `s3-jvm-<version>.jar` vs `s3-<version>.jar`). Users consuming dependencies through the Gradle Kotlin plugin will have this handled automatically for them.",
"issues": [
"awslabs/aws-sdk-kotlin#460"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ internal fun KotlinDependency.dependencyNotation(allowProjectNotation: Boolean =
val dep = this
return if (allowProjectNotation && sameProjectDeps.contains(dep)) {
val projectNotation = sameProjectDeps[dep]
"${dep.config}($projectNotation)"
"${dep.config.kmpName}($projectNotation)"
} else {
"${dep.config}(\"${dep.group}:${dep.artifact}:${dep.version}\")"
"${dep.config.kmpName}(\"${dep.group}:${dep.artifact}:${dep.version}\")"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,26 @@ class GradleGenerator : KotlinIntegration {

writer.write("val kotlinVersion: String by project")

val dependencies = delegator.dependencies.mapNotNull { it.properties["dependency"] as? KotlinDependency }.distinct()
val allDependencies = delegator.dependencies.mapNotNull { it.properties["dependency"] as? KotlinDependency }.distinct()

writer.write("")
.withBlock("dependencies {", "}") {
val orderedDependencies = dependencies.sortedWith(compareBy({ it.config }, { it.artifact }))
for (dependency in orderedDependencies) {
write(dependency.dependencyNotation())
writer
.write("")
.withBlock("kotlin {", "}") {
withBlock("sourceSets {", "}") {
allDependencies
.sortedWith(compareBy({ it.config }, { it.artifact }))
.groupBy { it.config.sourceSet }
.forEach { (sourceSet, dependencies) ->
withBlock("$sourceSet {", "}") {
withBlock("dependencies {", "}") {
dependencies
.map { it.dependencyNotation() }
.forEach(::write)
}
}
}
}
}
.write("")

val contents = writer.toString()
delegator.fileManifest.writeFile("build.gradle.kts", contents)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,9 @@ abstract class AbstractQueryFormUrlSerializerGenerator(
) {
// render the serde descriptors
descriptorGenerator(ctx, shape, members, writer).render()
if (shape.isUnionShape) {
SerializeUnionGenerator(ctx, members, writer, defaultTimestampFormat).render()
} else {
SerializeStructGenerator(ctx, members, writer, defaultTimestampFormat).render()
when (shape) {
is UnionShape -> SerializeUnionGenerator(ctx, shape, members, writer, defaultTimestampFormat).render()
else -> SerializeStructGenerator(ctx, members, writer, defaultTimestampFormat).render()
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ kotlin.native.ignoreDisabledTargets=true
org.gradle.jvmargs=-Xmx6g -XX:MaxPermSize=6g -XX:MaxMetaspaceSize=1G

# sdk
sdkVersion=0.15.3-SNAPSHOT
sdkVersion=0.16.0-SNAPSHOT

# codegen
smithyVersion=1.17.0
Expand Down
205 changes: 90 additions & 115 deletions services/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*
*/

import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
import org.jetbrains.kotlin.gradle.tasks.KotlinTest

plugins {
kotlin("jvm")
kotlin("multiplatform")
`maven-publish`
id("org.jetbrains.dokka")
}

val platforms = listOf("common", "jvm")

val sdkVersion: String by project
val kotlinVersion: String by project
val coroutinesVersion: String by project
Expand All @@ -17,149 +22,119 @@ val kotestVersion: String by project
val optinAnnotations = listOf(
"aws.smithy.kotlin.runtime.util.InternalApi",
"aws.sdk.kotlin.runtime.InternalSdkApi",
"kotlin.RequiresOptIn",
)

kotlin {
jvm() // Create a JVM target with the default name 'jvm'
}

subprojects {
group = "aws.sdk.kotlin"
version = sdkVersion

apply {
plugin("org.jetbrains.kotlin.jvm")
plugin("org.jetbrains.kotlin.multiplatform")
plugin("org.jetbrains.dokka")
}

// have generated sdk's opt-in to internal runtime features
kotlin.sourceSets.all {
optinAnnotations.forEach { languageSettings.optIn(it) }
}
logger.info("configuring: $project")

kotlin {
sourceSets.getByName("main") {
kotlin.srcDir("common/src")
kotlin.srcDir("generated-src/main/kotlin")
}
sourceSets.getByName("test") {
kotlin.srcDir("common/test")
kotlin.srcDir("generated-src/test")

dependencies {
implementation(kotlin("test-junit5"))
implementation("org.jetbrains.kotlin:kotlin-test-common:$kotlinVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
implementation(project(":aws-runtime:testing"))
implementation("io.kotest:kotest-assertions-core:$kotestVersion")
}
platforms.forEach { platform ->
configure(listOf(project)) {
apply(from = rootProject.file("gradle/$platform.gradle"))
}
}

tasks.withType<org.jetbrains.dokka.gradle.DokkaTaskPartial>().configureEach {
dokkaSourceSets {
named("main") {
platform.set(org.jetbrains.dokka.Platform.jvm)
sourceRoots.from(kotlin.sourceSets.getByName("main").kotlin.srcDirs)
kotlin {
sourceSets {
all {
val srcDir = if (name.endsWith("Main")) "src" else "test"
val resourcesPrefix = if (name.endsWith("Test")) "test-" else ""
// the name is always the platform followed by a suffix of either "Main" or "Test" (e.g. jvmMain, commonTest, etc)
val platform = name.substring(0, name.length - 4)
kotlin.srcDir("$platform/$srcDir")
resources.srcDir("$platform/${resourcesPrefix}resources")

languageSettings.progressiveMode = true

// have generated sdk's opt-in to internal runtime features
optinAnnotations.forEach { languageSettings.optIn(it) }
}
}
}

tasks.test {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
showStandardStreams = true
showStackTraces = true
showExceptions = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}


tasks.compileKotlin {
kotlinOptions {
jvmTarget = "1.8" // this is the default but it's better to be explicit (e.g. it may change in Kotlin 1.5)
allWarningsAsErrors = false // FIXME Tons of errors occur in generated code
}
}
tasks.compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8" // this is the default but it's better to be explicit (e.g. it may change in Kotlin 1.5)
allWarningsAsErrors = false // FIXME Tons of errors occur in generated code
// Enable coroutine runTests in 1.6.10
// NOTE: may be removed after coroutines-test runTests becomes stable
freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn"
}
}

// FIXME - we can remove this when we implement generated services as multiplatform.
setOutgoingVariantMetadata()
getByName("commonMain") {
kotlin.srcDir("generated-src/main/kotlin")
}

val sourcesJar by tasks.creating(Jar::class) {
group = "publishing"
description = "Assembles Kotlin sources jar"
classifier = "sources"
from(sourceSets.getByName("main").allSource)
}
getByName("commonTest") {
kotlin.srcDir("generated-src/test")

// FIXME - kotlin multiplatform configures publications for you so when we switch we can remove this
// and just apply "publish.gradle" from the set of root gradle scripts (just like we do for the runtime)
plugins.apply("maven-publish")
publishing {
publications {
create<MavenPublication>("sdk"){
from(components["java"])
artifact(sourcesJar)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
implementation(project(":aws-runtime:testing"))
}
}
}
}

apply(from = rootProject.file("gradle/publish.gradle"))

if (project.file("e2eTest").exists()) {

kotlin.target.compilations {
val main by getting
val e2eTest by creating {
defaultSourceSet {
kotlin.srcDir("e2eTest")
dependencies {
implementation(main.compileDependencyFiles + main.runtimeDependencyFiles + main.output.classesDirs)
if (project.file("e2eTest").exists()) {
jvm().compilations {
val main by getting
val e2eTest by creating {
defaultSourceSet {
kotlin.srcDir("e2eTest")

dependencies {
// Compile against the main compilation's compile classpath and outputs:
implementation(main.compileDependencyFiles + main.output.classesDirs)

implementation(kotlin("test"))
implementation(kotlin("test-junit5"))
implementation(project(":aws-runtime:testing"))
implementation(project(":tests:e2e-test-util"))
}
}

implementation(kotlin("test"))
implementation(kotlin("test-junit5"))
implementation(project(":aws-runtime:testing"))
implementation(project(":tests:e2e-test-util"))
kotlinOptions {
// Enable coroutine runTests in 1.6.10
// NOTE: may be removed after coroutines-test runTests becomes stable
freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn"
}
}
kotlinOptions {
// Enable coroutine runTests in 1.6.10
// NOTE: may be removed after coroutines-test runTests becomes stable
freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn"
}

tasks.register<Test>("e2eTest") {
description = "Run e2e service tests"
group = "verification"
classpath = compileDependencyFiles + runtimeDependencyFiles
testClassesDirs = output.classesDirs
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
showStandardStreams = true
showStackTraces = true
showExceptions = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
tasks.register<Test>("e2eTest") {
description = "Run e2e service tests"
group = "verification"

// Run the tests with the classpath containing the compile dependencies (including 'main'),
// runtime dependencies, and the outputs of this compilation:
classpath = compileDependencyFiles + runtimeDependencyFiles + output.allOutputs

// Run only the tests from this compilation's outputs:
testClassesDirs = output.classesDirs

useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
showStandardStreams = true
showStackTraces = true
showExceptions = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
}
}
}
}
}

dependencies {
dokkaPlugin(project(":dokka-aws"))
}

// fixes outgoing variant metadata: https://github.com/awslabs/smithy-kotlin/issues/258
fun Project.setOutgoingVariantMetadata() {
tasks.withType<JavaCompile>() {
val javaVersion = JavaVersion.VERSION_1_8.toString()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this probably needs an equivalent somewhere in the kotlin compilation options? It looks like we used to set it on line 78.

sourceCompatibility = javaVersion
targetCompatibility = javaVersion
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
allWarningsAsErrors = false // FIXME Tons of errors occur in generated code
jvmTarget = "1.8" // fixes outgoing variant metadata: https://github.com/awslabs/smithy-kotlin/issues/258
}
}

apply(from = rootProject.file("gradle/publish.gradle"))
}
4 changes: 3 additions & 1 deletion services/s3/e2eTest/S3TestUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ object S3TestUtils {

if (testBucket == null) {
testBucket = prefix + UUID.randomUUID()
println("Creating S3 bucket: $testBucket")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably be good to add an else branch and print that we are re-using an existing test bucket (which could happen if delete fails or tests are ended abruptly, etc).


client.createBucket {
bucket = testBucket
createBucketConfiguration {
Expand All @@ -42,7 +44,7 @@ object S3TestUtils {
}

client.waitUntilBucketExists { bucket = testBucket }
}
} else println("Using existing S3 bucket: $testBucket")

client.putBucketLifecycleConfiguration {
bucket = testBucket
Expand Down