1
1
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
2
2
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
3
+ import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
3
4
4
5
plugins {
5
6
application
@@ -9,6 +10,7 @@ plugins {
9
10
alias(libs.plugins.shadow)
10
11
kotlin(" jvm" )
11
12
kotlin(" plugin.serialization" )
13
+ alias(libs.plugins.openapi.generator)
12
14
}
13
15
14
16
description = " Model Server offering access to model storage"
@@ -28,7 +30,6 @@ dependencies {
28
30
implementation(libs.kotlin.serialization.json)
29
31
implementation(libs.kotlin.coroutines.core)
30
32
31
- implementation(project(" :api" ))
32
33
implementation(project(" :model-api" ))
33
34
implementation(project(" :model-server-api" ))
34
35
implementation(project(" :model-client" , configuration = " jvmRuntimeElements" ))
@@ -123,7 +124,7 @@ val cucumber = task("cucumber") {
123
124
// copies the openAPI specifications from the api folder into a resource
124
125
// folder so that they are packaged and deployed with the model-server
125
126
tasks.register<Copy >(" copyApis" ) {
126
- from(project( " :api " ) .layout.projectDirectory.dir(" openapi/specifications" ))
127
+ from(project.layout.projectDirectory.dir(" ../model-server- openapi/specifications" ))
127
128
include(" *.yaml" )
128
129
into(project.layout.buildDirectory.dir(" openapi/src/main/resources/api" ))
129
130
sourceSets[" main" ].resources.srcDir(project.layout.buildDirectory.dir(" openapi/src/main/resources/" ))
@@ -214,3 +215,86 @@ spotless {
214
215
'\n'*/
215
216
}
216
217
}
218
+
219
+ // OpenAPI integration
220
+ val basePackage = project.group.toString()
221
+ val openAPIgenerationPath = " ${project.layout.buildDirectory.get()} /generated/openapi"
222
+
223
+ // Pairs of the different OpenAPI files we use. Each pair must have its own 'category' as first argument as these
224
+ // are used to generate corresponding packages
225
+ val openApiFiles = listOf (
226
+ " public" to " model-server" ,
227
+ " operative" to " model-server-operative" ,
228
+ " light" to " model-server-light" ,
229
+ " html" to " model-server-html" ,
230
+ " deprecated" to " model-server-deprecated" ,
231
+ )
232
+
233
+ // generate tasks for each OpenAPI file
234
+ openApiFiles.forEach {
235
+ val targetTaskName = " openApiGenerate-${it.second} "
236
+ val targetPackageName = " $basePackage .api.${it.first} "
237
+ val outputPath = " $openAPIgenerationPath /${it.first} "
238
+ tasks.register<GenerateTask >(targetTaskName) {
239
+ // we let the Gradle OpenAPI generator plugin build data classes and API interfaces based on the provided
240
+ // OpenAPI specification. That way, the code is forced to stay in sync with the API specification.
241
+ generatorName.set(" kotlin-server" )
242
+ inputSpec.set(layout.projectDirectory.dir(" ../model-server-openapi/specifications" ).file(" ${it.second} .yaml" ).toString())
243
+ outputDir.set(outputPath)
244
+ packageName.set(targetPackageName)
245
+ apiPackage.set(targetPackageName)
246
+ modelPackage.set(targetPackageName)
247
+ // We use patched mustache so that only the necessary parts (i.e. resources and models)
248
+ // are generated. additionally we patch the used serialization framework as the `ktor` plugin
249
+ // uses a different one than we do in the model-server. The templates are based on
250
+ // https://github.com/OpenAPITools/openapi-generator/tree/809b3331a95b3c3b7bcf025d16ae09dc0682cd69/modules/openapi-generator/src/main/resources/kotlin-server
251
+ templateDir.set(" ${layout.projectDirectory.dir(" src/main/resources/openapi/templates" )} " )
252
+ configOptions.set(
253
+ mapOf (
254
+ // we use the ktor generator to generate server side resources and model (i.e. data classes)
255
+ " library" to " ktor" ,
256
+ // the generated artifacts are not built independently, thus no dedicated build files have to be generated
257
+ " omitGradleWrapper" to " true" ,
258
+ // the path to resource generation we need
259
+ " featureResources" to " true" ,
260
+ // disable features we do not use
261
+ " featureAutoHead" to " false" ,
262
+ " featureCompression" to " false" ,
263
+ " featureHSTS" to " false" ,
264
+ " featureMetrics" to " false" ,
265
+ ),
266
+ )
267
+ // generate only Paths and Models - only this set will produce the intended Paths.kt as well as the models
268
+ // the openapi generator is generally very picky and configuring it is rather complex
269
+ globalProperties.putAll(
270
+ mapOf (
271
+ " models" to " " ,
272
+ " apis" to " " ,
273
+ " supportingFiles" to " Paths.kt" ,
274
+ ),
275
+ )
276
+ }
277
+
278
+ // Ensure that the OpenAPI generator runs before starting to compile
279
+ tasks.named(" processResources" ) {
280
+ dependsOn(targetTaskName)
281
+ }
282
+ tasks.named(" compileKotlin" ) {
283
+ dependsOn(targetTaskName)
284
+ }
285
+ tasks.named(" runKtlintCheckOverMainSourceSet" ) {
286
+ dependsOn(targetTaskName)
287
+ }
288
+
289
+ // do not apply ktlint on the generated files
290
+ ktlint {
291
+ filter {
292
+ exclude {
293
+ it.file.toPath().toAbsolutePath().startsWith(outputPath)
294
+ }
295
+ }
296
+ }
297
+
298
+ // add openAPI generated artifacts to the sourceSets
299
+ sourceSets[" main" ].kotlin.srcDir(" $outputPath /src/main/kotlin" )
300
+ }
0 commit comments