Skip to content

Commit b1284b4

Browse files
authored
[plugin] fix compile dependency of test client (ExpediaGroup#1124)
`GraphQLGenerateTestClientTask` was extending `GraphQLGenerateClientTask` which meant that we were configuring all task of type `GraphQLGenerateClientTask` we were also configuring test client. Moved the common client generation logic to a new `AbstractGenerateClientTask` which is used by both client generation tasks.
1 parent 4f0720b commit b1284b4

File tree

7 files changed

+220
-188
lines changed

7 files changed

+220
-188
lines changed

examples/client/gradle-client/settings.gradle.kts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*
2+
* Copyright 2021 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.plugin.gradle.tasks
18+
19+
import com.expediagroup.graphql.plugin.gradle.actions.GenerateClientAction
20+
import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer
21+
import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar
22+
import org.gradle.api.DefaultTask
23+
import org.gradle.api.file.ConfigurableFileCollection
24+
import org.gradle.api.file.DirectoryProperty
25+
import org.gradle.api.file.RegularFileProperty
26+
import org.gradle.api.provider.ListProperty
27+
import org.gradle.api.provider.Property
28+
import org.gradle.api.tasks.Classpath
29+
import org.gradle.api.tasks.Input
30+
import org.gradle.api.tasks.InputFile
31+
import org.gradle.api.tasks.InputFiles
32+
import org.gradle.api.tasks.Optional
33+
import org.gradle.api.tasks.OutputDirectory
34+
import org.gradle.api.tasks.TaskAction
35+
import org.gradle.api.tasks.options.Option
36+
import org.gradle.workers.ClassLoaderWorkerSpec
37+
import org.gradle.workers.WorkQueue
38+
import org.gradle.workers.WorkerExecutor
39+
import java.io.File
40+
import javax.inject.Inject
41+
42+
/**
43+
* Generate GraphQL Kotlin client and corresponding data classes based on the provided GraphQL queries.
44+
*/
45+
@Suppress("UnstableApiUsage")
46+
abstract class AbstractGenerateClientTask : DefaultTask() {
47+
48+
@get:Classpath
49+
val pluginClasspath: ConfigurableFileCollection = project.objects.fileCollection()
50+
51+
/**
52+
* Path to GraphQL schema file that will be used to generate client code.
53+
*
54+
* **Required Property**: [schemaFileName] or [schemaFile] has to be provided.
55+
* **Command line property is**: `schemaFileName`.
56+
*/
57+
@Input
58+
@Optional
59+
@Option(option = "schemaFileName", description = "path to GraphQL schema file that will be used to generate the client code")
60+
val schemaFileName: Property<String> = project.objects.property(String::class.java)
61+
62+
/**
63+
* GraphQL schema file that will be used to generate client code.
64+
*
65+
* **Required Property**: [schemaFileName] or [schemaFile] has to be provided.
66+
*/
67+
@InputFile
68+
@Optional
69+
val schemaFile: RegularFileProperty = project.objects.fileProperty()
70+
71+
/**
72+
* Target package name for generated code.
73+
*
74+
* **Required Property**
75+
* **Command line property is**: `packageName`.
76+
*/
77+
@Input
78+
@Option(option = "packageName", description = "target package name to use for generated classes")
79+
val packageName: Property<String> = project.objects.property(String::class.java)
80+
81+
/**
82+
* Boolean flag indicating whether selection of deprecated fields is allowed or not.
83+
*
84+
* **Default value is:** `false`.
85+
* **Command line property is**: `allowDeprecatedFields`.
86+
*/
87+
@Input
88+
@Optional
89+
@Option(option = "allowDeprecatedFields", description = "boolean flag indicating whether selection of deprecated fields is allowed or not")
90+
val allowDeprecatedFields: Property<Boolean> = project.objects.property(Boolean::class.java)
91+
92+
/**
93+
* List of custom GraphQL scalar converters.
94+
*
95+
* ```kotlin
96+
* customScalars.add(GraphQLScalar("UUID", "java.util.UUID", "com.expediagroup.graphql.examples.client.UUIDScalarConverter"))
97+
* )
98+
*/
99+
@Input
100+
@Optional
101+
val customScalars: ListProperty<GraphQLScalar> = project.objects.listProperty(GraphQLScalar::class.java)
102+
103+
/**
104+
* Directory containing GraphQL queries. Defaults to `src/main/resources` when generating main sources and `src/test/resources`
105+
* when generating test client.
106+
*
107+
* Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
108+
*/
109+
@Input
110+
@Optional
111+
@Option(option = "queryFileDirectory", description = "directory containing query files")
112+
val queryFileDirectory: Property<String> = project.objects.property(String::class.java)
113+
114+
/**
115+
* List of query files to be processed. Instead of a list of files to be processed you can also specify [queryFileDirectory] directory
116+
* containing all the files. If this property is specified it will take precedence over the corresponding directory property.
117+
*/
118+
@InputFiles
119+
@Optional
120+
val queryFiles: ConfigurableFileCollection = project.objects.fileCollection()
121+
122+
@Input
123+
@Optional
124+
@Option(option = "serializer", description = "JSON serializer that will be used to generate the data classes.")
125+
val serializer: Property<GraphQLSerializer> = project.objects.property(GraphQLSerializer::class.java)
126+
127+
@OutputDirectory
128+
val outputDirectory: DirectoryProperty = project.objects.directoryProperty()
129+
130+
@Inject
131+
abstract fun getWorkerExecutor(): WorkerExecutor
132+
133+
init {
134+
group = "GraphQL"
135+
description = "Generate HTTP client from the specified GraphQL queries."
136+
137+
allowDeprecatedFields.convention(false)
138+
customScalars.convention(emptyList())
139+
serializer.convention(GraphQLSerializer.JACKSON)
140+
queryFileDirectory.convention("${project.projectDir}/src/main/resources")
141+
outputDirectory.convention(project.layout.buildDirectory.dir("generated/source/graphql/main"))
142+
}
143+
144+
@Suppress("EXPERIMENTAL_API_USAGE")
145+
@TaskAction
146+
fun generateGraphQLClientAction() {
147+
logger.debug("generating GraphQL client")
148+
149+
val graphQLSchema = when {
150+
schemaFile.isPresent -> schemaFile.get().asFile
151+
schemaFileName.isPresent -> File(schemaFileName.get())
152+
else -> throw RuntimeException("schema not available")
153+
}
154+
if (!graphQLSchema.isFile) {
155+
throw RuntimeException("specified schema file does not exist")
156+
}
157+
158+
val targetPackage = packageName.orNull ?: throw RuntimeException("package not specified")
159+
val targetQueryFiles: List<File> = when {
160+
queryFiles.files.isNotEmpty() -> queryFiles.files.toList()
161+
queryFileDirectory.isPresent ->
162+
File(queryFileDirectory.get())
163+
.listFiles { file -> file.extension == "graphql" }
164+
?.toList() ?: throw RuntimeException("exception while looking up the query files")
165+
else -> throw RuntimeException("no query files found")
166+
}
167+
168+
if (targetQueryFiles.isEmpty()) {
169+
throw RuntimeException("no query files specified")
170+
}
171+
172+
val targetDirectory = outputDirectory.get().asFile
173+
if (!targetDirectory.isDirectory && !targetDirectory.mkdirs()) {
174+
throw RuntimeException("failed to generate generated source directory = $targetDirectory")
175+
}
176+
177+
logConfiguration(graphQLSchema, targetQueryFiles)
178+
val workQueue: WorkQueue = getWorkerExecutor().classLoaderIsolation { workerSpec: ClassLoaderWorkerSpec ->
179+
workerSpec.classpath.from(pluginClasspath)
180+
logger.debug("worker classpath: \n${workerSpec.classpath.files.joinToString("\n")}")
181+
}
182+
183+
workQueue.submit(GenerateClientAction::class.java) { parameters ->
184+
parameters.packageName.set(targetPackage)
185+
parameters.allowDeprecated.set(allowDeprecatedFields)
186+
parameters.customScalars.set(customScalars)
187+
parameters.serializer.set(serializer)
188+
parameters.schemaFile.set(graphQLSchema)
189+
parameters.queryFiles.set(targetQueryFiles)
190+
parameters.targetDirectory.set(targetDirectory)
191+
}
192+
workQueue.await()
193+
logger.debug("successfully generated GraphQL HTTP client")
194+
}
195+
196+
private fun logConfiguration(schema: File, queryFiles: List<File>) {
197+
logger.debug("GraphQL Client generator configuration:")
198+
logger.debug(" schema file = ${schema.path}")
199+
logger.debug(" queries")
200+
queryFiles.forEach {
201+
logger.debug(" - ${it.name}")
202+
}
203+
logger.debug(" packageName = $packageName")
204+
logger.debug(" allowDeprecatedFields = $allowDeprecatedFields")
205+
logger.debug(" converters")
206+
customScalars.get().forEach { (customScalar, type, converter) ->
207+
logger.debug(" - custom scalar = $customScalar")
208+
logger.debug(" |- type = $type")
209+
logger.debug(" |- converter = $converter")
210+
}
211+
logger.debug("")
212+
logger.debug("-- end GraphQL Client generator configuration --")
213+
}
214+
}

0 commit comments

Comments
 (0)