Skip to content

Commit 2e63572

Browse files
authored
[plugin] support generating graphql client test sources (#718)
* [plugin] support generating graphql client test sources Generate GraphQL client Gradle task and Maven Mojo now accept optional `generateTestSources` boolean parameter to indicate generation of test sources. Resolves: #706 * fix example maven client * fix test * separate generateTestClient task/mojo * update docs * revert some docs to old format
1 parent 12ac885 commit 2e63572

File tree

28 files changed

+1231
-372
lines changed

28 files changed

+1231
-372
lines changed

docs/plugins/gradle-plugin.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ graphql {
4141
allowDeprecatedFields = false
4242
// Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values.
4343
converters.put("UUID", ScalarConverterMapping("java.util.UUID", "com.example.UUIDScalarConverter"))
44+
// Boolean flag indicating whether generated GraphQL client should be added to main or test sources.
45+
generateTestSources = false
4446
}
4547
```
4648

@@ -66,7 +68,7 @@ and could be used as an alternative to `graphqlIntrospectSchema` to generate inp
6668

6769
Task that generates GraphQL Kotlin client and corresponding data classes based on the provided GraphQL queries that are
6870
evaluated against target Graphql schema. Individual clients with their specific data models are generated for each query
69-
file and are placed under specified `packageName`.
71+
file and are placed under specified `packageName`. Generated code is automatically added to the project main source set.
7072

7173
**Properties**
7274

@@ -80,6 +82,24 @@ file and are placed under specified `packageName`.
8082
| `schemaFile` | File | `schemaFileName` or `schemaFile` has to be provided | GraphQL schema file that will be used to generate client code. |
8183
| `schemaFileName` | String | `schemaFileName` or `schemaFile` has to be provided | Path to GraphQL schema file that will be used to generate client code.<br/>**Command line property is**: `schemaFileName`. |
8284

85+
### graphqlGenerateTestClient
86+
87+
Task that generates GraphQL Kotlin test client and corresponding data classes based on the provided GraphQL queries that are
88+
evaluated against target Graphql schema. Individual test clients with their specific data models are generated for each query
89+
file and are placed under specified `packageName`. Generated code is automatically added to the project test source set.
90+
91+
**Properties**
92+
93+
| Property | Type | Required | Description |
94+
| -------- | ---- | -------- | ----------- |
95+
| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.<br/>**Default value is:** `false`.<br/>**Command line property is**: `allowDeprecatedFields`. |
96+
| `converters` | Map<String, ScalarConverter> | | Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values. |
97+
| `packageName` | String | yes | Target package name for generated code.<br/>**Command line property is**: `packageName`. |
98+
| `queryFiles` | FileCollection | | List of query files to be processed. Instead of a list of files to be processed you can specify `queryFileDirectory` directory instead. If this property is specified it will take precedence over the corresponding directory property. |
99+
| `queryFileDirectory` | String | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.<br/>**Default value is:** `src/test/resources`.<br/>**Command line property is**: `queryFileDirectory`. |
100+
| `schemaFile` | File | `schemaFileName` or `schemaFile` has to be provided | GraphQL schema file that will be used to generate client code. |
101+
| `schemaFileName` | String | `schemaFileName` or `schemaFile` has to be provided | Path to GraphQL schema file that will be used to generate client code.<br/>**Command line property is**: `schemaFileName`. |
102+
83103
### graphqlIntrospectSchema
84104

85105
Task that executes GraphQL introspection query against specified `endpoint` and saves the underlying schema file as

docs/plugins/maven-plugin.md

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,51 @@ Generate GraphQL client code based on the provided GraphQL schema and target que
4545
| -------- | ---- | -------- | ----------- |
4646
| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.<br/>**Default value is:** `false`.<br/>**User property is**: `graphql.allowDeprecatedFields`. |
4747
| `converters` | Map<String, ScalarConverter> | | Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values. |
48-
| `outputDirectory` | File | | Target directory where to store generated files.<br/>**Default value is**: `${project.build.directory}/generated/sources/graphql` |
48+
| `outputDirectory` | File | | Target directory where to store generated files.<br/>**Default value is**: `${project.build.directory}/generated-sources/graphql` |
4949
| `packageName` | String | yes | Target package name for generated code.<br/>**User property is**: `graphql.packageName`. |
5050
| `queryFileDirectory` | File | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.<br/>**Default value is:** `src/main/resources`. |
5151
| `queryFiles` | List<File> | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. |
5252
| `schemaFile` | String | yes | GraphQL schema file that will be used to generate client code.<br/>**User property is**: `graphql.schemaFile`. |
5353

54+
**Parameter Details**
55+
56+
* *converters* - Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values.
57+
58+
```xml
59+
<converters>
60+
<!-- custom scalar type -->
61+
<UUID>
62+
<!-- fully qualified Java class name of a custom scalar type -->
63+
<type>java.util.UUID</type>
64+
<!-- fully qualified Java class name of a custom com.expediagroup.graphql.client.converter.ScalarConverter
65+
used to convert to/from raw JSON and scalar type -->
66+
<converter>com.example.UUIDScalarConverter</converter>
67+
</UUID>
68+
</converters>
69+
```
70+
71+
### generateTestClient
72+
73+
Generate GraphQL test client code based on the provided GraphQL schema and target queries.
74+
75+
**Attributes**
76+
77+
* *Default Lifecycle Phase*: `generate-test-sources`
78+
* *Requires Maven Project*
79+
* Generated classes are automatically added to the list of test compiled sources.
80+
81+
**Parameters**
82+
83+
| Property | Type | Required | Description |
84+
| -------- | ---- | -------- | ----------- |
85+
| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.<br/>**Default value is:** `false`.<br/>**User property is**: `graphql.allowDeprecatedFields`. |
86+
| `converters` | Map<String, ScalarConverter> | | Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values. |
87+
| `outputDirectory` | File | | Target directory where to store generated files.<br/>**Default value is**: `${project.build.directory}/generated-test-sources/graphql` |
88+
| `packageName` | String | yes | Target package name for generated code.<br/>**User property is**: `graphql.packageName`. |
89+
| `queryFileDirectory` | File | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.<br/>**Default value is:** `src/test/resources`. |
90+
| `queryFiles` | List<File> | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. |
91+
| `schemaFile` | String | yes | GraphQL schema file that will be used to generate client code.<br/>**User property is**: `graphql.schemaFile`. |
92+
5493
**Parameter Details**
5594

5695
* *converters* - Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values.
@@ -185,6 +224,9 @@ Mojo can also be configured in your Maven build file and it provides additional
185224
This will process all GraphQL queries located under `src/main/resources` and generate corresponding GraphQL Kotlin clients.
186225
Generated classes will be automatically added to the project compile sources.
187226

227+
>NOTE: You might need to explicitly add generated clients to your project sources for your IDE to recognize them. See
228+
>[build-helper-maven-plugin](https://www.mojohaus.org/build-helper-maven-plugin/) for details.
229+
188230
### Generating Client with Custom Scalars
189231

190232
By default, all custom GraphQL scalars will be serialized as Strings. You can override this default behavior by specifying
@@ -277,6 +319,6 @@ This generated schema is subsequently used to generate GraphQL client code based
277319
</plugin>
278320
```
279321

280-
NOTE: Both `introspectSchema` and `generateClient` goals are bound to the same `generate-sources` Maven lifecycle phase.
281-
As opposed to Gradle, Maven does not support explicit dependencies between different goals and they will be executed in
282-
the order they are defined in your `pom.xml` build file.
322+
>NOTE: Both `introspectSchema` and `generateClient` goals are bound to the same `generate-sources` Maven lifecycle phase.
323+
>As opposed to Gradle, Maven does not support explicit ordering of goals. Maven Mojos will be executed in the order they
324+
>are defined in your `pom.xml` build file.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rootProject.name = "graphql-kotlin-gradle-client-example"

examples/client/maven-client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
</goals>
9292
<configuration>
9393
<sources>
94-
<source>${project.build.directory}/generated/sources/graphql</source>
94+
<source>${project.build.directory}/generated-sources/graphql</source>
9595
</sources>
9696
</configuration>
9797
</execution>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rootProject.name = "graphql-kotlin-simple-server-example"

plugins/graphql-kotlin-gradle-plugin/README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ and could be used as an alternative to `graphqlIntrospectSchema` to generate inp
5151

5252
Task that generates GraphQL Kotlin client and corresponding data classes based on the provided GraphQL queries that are
5353
evaluated against target Graphql schema. Individual clients with their specific data models are generated for each query
54-
file and are placed under specified `packageName`.
54+
file and are placed under specified `packageName`. Generated code is automatically added to the project main source set.
5555

5656
**Properties**
5757

@@ -65,6 +65,24 @@ file and are placed under specified `packageName`.
6565
| `schemaFile` | File | `schemaFileName` or `schemaFile` has to be provided | GraphQL schema file that will be used to generate client code. |
6666
| `schemaFileName` | String | `schemaFileName` or `schemaFile` has to be provided | Path to GraphQL schema file that will be used to generate client code.<br/>**Command line property is**: `schemaFileName`. |
6767

68+
### graphqlGenerateTestClient
69+
70+
Task that generates GraphQL Kotlin test client and corresponding data classes based on the provided GraphQL queries that are
71+
evaluated against target Graphql schema. Individual test clients with their specific data models are generated for each query
72+
file and are placed under specified `packageName`. Generated code is automatically added to the project test source set.
73+
74+
**Properties**
75+
76+
| Property | Type | Required | Description |
77+
| -------- | ---- | -------- | ----------- |
78+
| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.<br/>**Default value is:** `false`.<br/>**Command line property is**: `allowDeprecatedFields`. |
79+
| `converters` | Map<String, ScalarConverter> | | Custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values. |
80+
| `packageName` | String | yes | Target package name for generated code.<br/>**Command line property is**: `packageName`. |
81+
| `queryFiles` | FileCollection | | List of query files to be processed. Instead of a list of files to be processed you can specify `queryFileDirectory` directory instead. If this property is specified it will take precedence over the corresponding directory property. |
82+
| `queryFileDirectory` | String | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.<br/>**Default value is:** `src/test/resources`.<br/>**Command line property is**: `queryFileDirectory`. |
83+
| `schemaFile` | File | `schemaFileName` or `schemaFile` has to be provided | GraphQL schema file that will be used to generate client code. |
84+
| `schemaFileName` | String | `schemaFileName` or `schemaFile` has to be provided | Path to GraphQL schema file that will be used to generate client code.<br/>**Command line property is**: `schemaFileName`. |
85+
6886
### graphqlIntrospectSchema
6987

7088
Task that executes GraphQL introspection query against specified `endpoint` and saves the underlying schema file as

plugins/graphql-kotlin-gradle-plugin/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ plugins {
55
id("com.gradle.plugin-publish")
66
}
77

8-
val kotlinVersion: String by project
98
val kotlinCoroutinesVersion: String by project
109
val wireMockVersion: String by project
1110

@@ -59,7 +58,10 @@ tasks {
5958
}
6059
}
6160
test {
61+
val kotlinVersion: String by project
62+
val junitVersion: String by project
6263
systemProperty("graphQLKotlinVersion", project.version)
6364
systemProperty("kotlinVersion", kotlinVersion)
65+
systemProperty("junitVersion", junitVersion)
6466
}
6567
}

plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLGradlePlugin.kt

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ package com.expediagroup.graphql.plugin.gradle
1818

1919
import com.expediagroup.graphql.plugin.gradle.tasks.DOWNLOAD_SDL_TASK_NAME
2020
import com.expediagroup.graphql.plugin.gradle.tasks.GENERATE_CLIENT_TASK_NAME
21+
import com.expediagroup.graphql.plugin.gradle.tasks.GENERATE_TEST_CLIENT_TASK_NAME
2122
import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLDownloadSDLTask
2223
import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask
2324
import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLIntrospectSchemaTask
2425
import com.expediagroup.graphql.plugin.gradle.tasks.INTROSPECT_SCHEMA_TASK_NAME
2526
import org.gradle.api.Plugin
2627
import org.gradle.api.Project
2728
import org.gradle.api.tasks.SourceSetContainer
29+
import java.io.File
2830

2931
private const val PLUGIN_EXTENSION_NAME = "graphql"
3032

@@ -39,19 +41,17 @@ class GraphQLGradlePlugin : Plugin<Project> {
3941
project.tasks.register(INTROSPECT_SCHEMA_TASK_NAME, GraphQLIntrospectSchemaTask::class.java)
4042
project.tasks.register(DOWNLOAD_SDL_TASK_NAME, GraphQLDownloadSDLTask::class.java)
4143
project.tasks.register(GENERATE_CLIENT_TASK_NAME, GraphQLGenerateClientTask::class.java) { generateClientTask ->
42-
val compileKotlinTask = project.tasks.findByPath("compileKotlin")
43-
if (compileKotlinTask == null) {
44-
throw RuntimeException("compileKotlin task not found")
45-
} else {
46-
compileKotlinTask.dependsOn(generateClientTask.path)
47-
}
44+
configureCompileTaskDependency(project = project, generateClientTaskPath = generateClientTask.path)
4845

49-
// configure generated directory source sets
50-
val outputDirectory = generateClientTask.outputDirectory.get().asFile
51-
outputDirectory.mkdirs()
46+
generateClientTask.queryFileDirectory.convention("${project.projectDir}/src/main/resources")
47+
generateClientTask.outputDirectory.convention(project.layout.buildDirectory.dir("generated/source/graphql/main"))
48+
}
49+
project.tasks.register(GENERATE_TEST_CLIENT_TASK_NAME, GraphQLGenerateClientTask::class.java) { generateTestClientTask ->
50+
configureCompileTaskDependency(project = project, generateClientTaskPath = generateTestClientTask.path, compileTaskName = "compileTestKotlin")
5251

53-
val sourceSetContainer = project.findProperty("sourceSets") as? SourceSetContainer
54-
sourceSetContainer?.findByName("main")?.java?.srcDir(outputDirectory.path)
52+
generateTestClientTask.description = "Generate HTTP test client from the specified GraphQL queries."
53+
generateTestClientTask.queryFileDirectory.convention("${project.projectDir}/src/test/resources")
54+
generateTestClientTask.outputDirectory.convention(project.layout.buildDirectory.dir("generated/source/graphql/test"))
5555
}
5656

5757
project.afterEvaluate {
@@ -75,6 +75,29 @@ class GraphQLGradlePlugin : Plugin<Project> {
7575
generateClientTask.schemaFile.convention(downloadSDLTask.outputFile)
7676
}
7777
}
78+
79+
project.tasks.named(GENERATE_CLIENT_TASK_NAME, GraphQLGenerateClientTask::class.java) { task ->
80+
configureProjectSourceSet(project = project, outputDirectory = task.outputDirectory.get().asFile)
81+
}
82+
project.tasks.named(GENERATE_TEST_CLIENT_TASK_NAME, GraphQLGenerateClientTask::class.java) { task ->
83+
configureProjectSourceSet(project = project, outputDirectory = task.outputDirectory.get().asFile, targetSourceSet = "test")
84+
}
7885
}
7986
}
87+
88+
private fun configureCompileTaskDependency(project: Project, generateClientTaskPath: String, compileTaskName: String = "compileKotlin") {
89+
val compileKotlinTask = project.tasks.findByPath(compileTaskName)
90+
if (compileKotlinTask == null) {
91+
throw RuntimeException("$compileKotlinTask task not found")
92+
} else {
93+
compileKotlinTask.dependsOn(generateClientTaskPath)
94+
}
95+
}
96+
97+
private fun configureProjectSourceSet(project: Project, outputDirectory: File, targetSourceSet: String = "main") {
98+
outputDirectory.mkdirs()
99+
100+
val sourceSetContainer = project.findProperty("sourceSets") as? SourceSetContainer
101+
sourceSetContainer?.findByName(targetSourceSet)?.java?.srcDir(outputDirectory.path)
102+
}
80103
}

plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/tasks/GraphQLGenerateClientTask.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import org.gradle.api.file.Directory
2525
import org.gradle.api.file.RegularFileProperty
2626
import org.gradle.api.provider.MapProperty
2727
import org.gradle.api.provider.Property
28-
import org.gradle.api.provider.Provider
2928
import org.gradle.api.tasks.Input
3029
import org.gradle.api.tasks.InputFile
3130
import org.gradle.api.tasks.InputFiles
@@ -36,6 +35,7 @@ import org.gradle.api.tasks.options.Option
3635
import java.io.File
3736

3837
internal const val GENERATE_CLIENT_TASK_NAME: String = "graphqlGenerateClient"
38+
internal const val GENERATE_TEST_CLIENT_TASK_NAME: String = "graphqlGenerateTestClient"
3939

4040
/**
4141
* Generate GraphQL Kotlin client and corresponding data classes based on the provided GraphQL queries.
@@ -97,13 +97,14 @@ open class GraphQLGenerateClientTask : DefaultTask() {
9797
val converters: MapProperty<String, ScalarConverterMapping> = project.objects.mapProperty(String::class.java, ScalarConverterMapping::class.java)
9898

9999
/**
100-
* Directory containing GraphQL queries, defaults to `src/main/resources`.
100+
* Directory containing GraphQL queries. Defaults to `src/main/resources` when generating main sources and `src/test/resources`
101+
* when generating test client.
101102
*
102103
* Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
103104
*/
104105
@Input
105106
@Optional
106-
@Option(option = "queryFileDirectory", description = "directory containing query files, defaults to src/main/resources")
107+
@Option(option = "queryFileDirectory", description = "directory containing query files")
107108
val queryFileDirectory: Property<String> = project.objects.property(String::class.java)
108109

109110
/**
@@ -115,13 +116,12 @@ open class GraphQLGenerateClientTask : DefaultTask() {
115116
val queryFiles: ConfigurableFileCollection = project.objects.fileCollection()
116117

117118
@OutputDirectory
118-
val outputDirectory: Provider<Directory> = project.layout.buildDirectory.dir("generated/source/graphql")
119+
val outputDirectory: Property<Directory> = project.objects.directoryProperty()
119120

120121
init {
121122
group = "GraphQL"
122123
description = "Generate HTTP client from the specified GraphQL queries."
123124

124-
queryFileDirectory.convention("${project.projectDir}/src/main/resources")
125125
allowDeprecatedFields.convention(false)
126126
converters.convention(emptyMap())
127127
}

0 commit comments

Comments
 (0)