Skip to content

Commit 7042cf8

Browse files
authored
chore: abstract codegen logic into a plugin (#457)
1 parent 5133dd0 commit 7042cf8

File tree

15 files changed

+640
-225
lines changed

15 files changed

+640
-225
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ val lintPaths = listOf(
149149
"aws-runtime/**/*.kt",
150150
"examples/**/*.kt",
151151
"dokka-aws/**/*.kt",
152+
"gradle/sdk-plugins/src/**/*.kt",
152153
"services/**/*.kt",
153154
"!services/*/generated-src/**/*.kt"
154155
)

codegen/protocol-tests/build.gradle.kts

Lines changed: 59 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,25 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0.
44
*/
5+
import aws.sdk.kotlin.gradle.codegen.dsl.smithyKotlinPlugin
56
import software.amazon.smithy.gradle.tasks.SmithyBuild
67

78
plugins {
8-
id("software.amazon.smithy")
9+
id("aws.sdk.kotlin.codegen")
910
}
1011

1112
description = "Smithy protocol test suite"
1213

13-
buildscript {
14-
val smithyVersion: String by project
15-
dependencies {
16-
classpath("software.amazon.smithy:smithy-cli:$smithyVersion")
17-
}
18-
}
19-
20-
2114
val smithyVersion: String by project
2215
dependencies {
2316
implementation("software.amazon.smithy:smithy-aws-protocol-tests:$smithyVersion")
24-
implementation(project(":codegen:smithy-aws-kotlin-codegen"))
2517
}
2618

19+
data class ProtocolTest(val projectionName: String, val serviceShapeId: String, val sdkId: String? = null) {
20+
val packageName: String = projectionName.toLowerCase().filter { it.isLetterOrDigit() }
21+
}
22+
23+
2724
// The following section exposes Smithy protocol test suites as gradle test targets
2825
// for the configured protocols in [enabledProtocols].
2926
val enabledProtocols = listOf(
@@ -41,157 +38,96 @@ val enabledProtocols = listOf(
4138
ProtocolTest("machinelearning", "com.amazonaws.machinelearning#AmazonML_20141212", sdkId = "Machine Learning"),
4239
)
4340

44-
// This project doesn't produce a JAR.
45-
tasks["jar"].enabled = false
46-
47-
// Run the SmithyBuild task manually since this project needs the built JAR
48-
// from smithy-aws-kotlin-codegen.
49-
tasks["smithyBuildJar"].enabled = false
50-
51-
task("generateSmithyBuild") {
52-
group = "codegen"
53-
description = "generate smithy-build.json"
54-
val buildFile = projectDir.resolve("smithy-build.json")
55-
doFirst {
56-
buildFile.writeText(generateSmithyBuild(enabledProtocols))
41+
codegen {
42+
enabledProtocols.forEach { test ->
43+
projections.register(test.projectionName) {
44+
transforms = listOf(
45+
"""
46+
{
47+
"name": "includeServices",
48+
"args": {
49+
"services": ["${test.serviceShapeId}"]
50+
}
51+
}
52+
"""
53+
)
54+
55+
smithyKotlinPlugin {
56+
serviceShapeId = test.serviceShapeId
57+
packageName = "aws.sdk.kotlin.services.${test.packageName}"
58+
packageVersion = "1.0"
59+
sdkId = test.sdkId
60+
buildSettings {
61+
generateFullProject = true
62+
optInAnnotations = listOf(
63+
"aws.smithy.kotlin.runtime.util.InternalApi",
64+
"aws.sdk.kotlin.runtime.InternalSdkApi"
65+
)
66+
}
67+
}
68+
}
5769
}
58-
outputs.file(buildFile)
5970
}
6071

61-
// Remove generated model file for clean
62-
tasks["clean"].doFirst {
63-
delete("smithy-build.json")
64-
}
72+
tasks.named<SmithyBuild>("generateSmithyProjections") {
73+
// NOTE: The protocol tests are published to maven as a jar, this ensures that
74+
// the aws-protocol-tests dependency is found when generating code such that the `includeServices` transform
75+
// actually works
76+
addCompileClasspath = true
6577

66-
tasks.create<SmithyBuild>("generateSdk") {
67-
group = "codegen"
6878
// ensure the generated clients use the same version of the runtime as the aws aws-runtime
6979
val smithyKotlinVersion: String by project
7080
doFirst {
7181
System.setProperty("smithy.kotlin.codegen.clientRuntimeVersion", smithyKotlinVersion)
7282
}
73-
addRuntimeClasspath = true
74-
dependsOn(tasks["generateSmithyBuild"])
75-
inputs.file(projectDir.resolve("smithy-build.json"))
76-
// ensure smithy-aws-kotlin-codegen is up to date
77-
inputs.files(configurations.compileClasspath)
78-
}
79-
80-
// force rebuild every time while developing
81-
tasks["generateSdk"].outputs.upToDateWhen { false }
82-
83-
data class ProtocolTest(val projectionName: String, val serviceShapeId: String, val sdkId: String? = null) {
84-
val packageName: String
85-
get() = projectionName.toLowerCase().filter { it.isLetterOrDigit() }
86-
}
87-
88-
89-
// Generates a smithy-build.json file by creating a new projection.
90-
// The generated smithy-build.json file is not committed to git since
91-
// it's rebuilt each time codegen is performed.
92-
fun generateSmithyBuild(tests: List<ProtocolTest>): String {
93-
val projections = tests.joinToString(",") { test ->
94-
val sdkIdEntry = test.sdkId?.let { """"sdkId": "$it",""" } ?: ""
95-
"""
96-
"${test.projectionName}": {
97-
"transforms": [
98-
{
99-
"name": "includeServices",
100-
"args": {
101-
"services": [
102-
"${test.serviceShapeId}"
103-
]
104-
}
105-
}
106-
],
107-
"plugins": {
108-
"kotlin-codegen": {
109-
"service": "${test.serviceShapeId}",
110-
"package": {
111-
"name": "aws.sdk.kotlin.services.${test.packageName}",
112-
"version": "1.0"
113-
},
114-
$sdkIdEntry
115-
"build": {
116-
"rootProject": true,
117-
"optInAnnotations": [
118-
"aws.smithy.kotlin.runtime.util.InternalApi",
119-
"aws.sdk.kotlin.runtime.InternalSdkApi"
120-
]
121-
}
122-
}
123-
}
124-
}
125-
"""
126-
}
127-
return """
128-
{
129-
"version": "1.0",
130-
"projections": {
131-
$projections
132-
}
133-
}
134-
""".trimIndent()
13583
}
13684

13785
open class ProtocolTestTask : DefaultTask() {
13886
/**
139-
* The protocol name
87+
* The projection
14088
*/
14189
@get:Input
142-
var protocol: String = ""
90+
var projection: aws.sdk.kotlin.gradle.codegen.dsl.SmithyProjection? = null
14391

144-
/**
145-
* The plugin name to use
146-
*/
147-
@get:Input
148-
var plugin: String = ""
149-
150-
/**
151-
* The build directory for the task
152-
*/
153-
val generatedBuildDir: File
154-
@OutputDirectory
155-
get() = project.buildDir.resolve("smithyprojections/${project.name}/$protocol/$plugin")
15692

15793
@TaskAction
15894
fun runTests() {
159-
require(protocol.isNotEmpty()) { "protocol name must be specified" }
160-
require(plugin.isNotEmpty()) { "plugin name must be specified" }
161-
162-
println("[$protocol] buildDir: $generatedBuildDir")
163-
if (!generatedBuildDir.exists()) {
164-
throw GradleException("$generatedBuildDir does not exist")
95+
val projection = requireNotNull(projection) { "projection is required task input" }
96+
println("[${projection.name}] buildDir: ${projection.projectionRootDir}")
97+
if (!projection.projectionRootDir.exists()) {
98+
throw GradleException("${projection.projectionRootDir} does not exist")
16599
}
166100
val wrapper = if (System.getProperty("os.name").toLowerCase().contains("windows")) "gradlew.bat" else "gradlew"
167101
val gradlew = project.rootProject.file(wrapper).absolutePath
168102

169103
// NOTE - this still requires us to publish to maven local.
170104
project.exec {
171-
workingDir = generatedBuildDir
105+
workingDir = projection.projectionRootDir
172106
executable = gradlew
173107
args = listOf("test")
174108
}
175109
}
176110
}
177111

178-
enabledProtocols.forEach {
179-
val protocolName = it.projectionName
112+
val codegenTask = tasks.getByName("generateSmithyProjections")
113+
codegen.projections.forEach {
114+
val protocolName = it.name
180115

181-
val protocolTestTask = tasks.register<ProtocolTestTask>("testProtocol-$protocolName") {
182-
dependsOn(tasks["generateSdk"])
116+
tasks.register<ProtocolTestTask>("testProtocol-$protocolName") {
117+
dependsOn(codegenTask)
183118
group = "Verification"
184-
protocol = protocolName
185-
plugin = "kotlin-codegen"
186-
}.get()
119+
projection = it
120+
}
187121

188122
// FIXME This is a hack to work around how protocol tests aren't in the actual service model and thus codegen
189123
// separately from service customizations.
190-
tasks.create<Copy>("copyStaticFiles-$protocolName") {
124+
val copyStaticFiles = tasks.register<Copy>("copyStaticFiles-$protocolName") {
125+
group = "codegen"
191126
from(rootProject.projectDir.resolve("services/$protocolName/common/src"))
192-
into(protocolTestTask.generatedBuildDir.resolve("src/main/kotlin/"))
193-
tasks["generateSdk"].finalizedBy(this)
127+
into(it.projectionRootDir.resolve("src/main/kotlin/"))
194128
}
129+
130+
codegenTask.finalizedBy(copyStaticFiles)
195131
}
196132

197133
tasks.register("testAllProtocols") {

0 commit comments

Comments
 (0)