Skip to content

Commit ac3a5f4

Browse files
authored
Invoke the Apollo compiler directly, when possible (#62)
* Do not use Gradle continuous mode * Retrieve configuration via a task rather than via tooling models, and use the Apollo Compiler * Rename GradleToolingModelService -> ApolloKotlinProjectModelService * Adapt to renames in the Gradle plugin * Retrieve Telemetry data from project / service models * Move ProjectModel, ServiceModel to :apollo-tooling * Use plugin dependencies * Add operationManifestFile * Renames/moves * Use EntryPoints APIs * Less verbose log * Generate data builders * Cache IDEs * Use published version of Apollo Kotlin * Prepare for v5 releace * Add a note about supported AK versions * Revert intellij-platform-plugin to 2.8.0 * Changelog tweak
1 parent 3e9f11b commit ac3a5f4

28 files changed

+1206
-469
lines changed

CHANGELOG.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,27 @@
33
PUT_CHANGELOG_HERE
44

55
# Version 5.0.0
6-
_2025-07-01_
6+
7+
_2025-09-01_
8+
9+
> [!NOTE]
10+
> Starting with this release, the plugin no longer depends on the [JetBrains GraphQL plugin](https://plugins.jetbrains.com/plugin/8097-graphql).
11+
> Instead, it includes a fork of that plugin's code which has been adapted to work better with Apollo Kotlin (#43).
12+
>
13+
> If you are upgrading the plugin from 4.x, the IDE will ask you to disable or uninstall the JetBrains GraphQL plugin,
14+
> as both plugins cannot be used at the same time.
15+
16+
- Overhaul of the code generation mechanism (#62).<br>
17+
Code generation is now using the Apollo Compiler directly, instead of
18+
invoking the Gradle codegen task, when possible (projects using Apollo Kotlin v5+). This results in faster code generation
19+
and lower memory consumption. For projects using Apollo Kotlin < v5, the Gradle task is still invoked, but no longer with
20+
the`--continuous` flag, which avoids running a dedicated Gradle daemon (#36).
21+
- Better `@link` support (#55)
22+
- Add received date to the cache viewer (#56)
23+
- Support descriptions on executable definitions (#53)
24+
- Make the graphql folder stand out (#54)
25+
- Various crash and bug fixes
26+
27+
#### Compatibility
28+
29+
This version supports projects using Apollo Kotlin v3.x, v4.x and v5.x.

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016-present Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
4+
Copyright (c) 2015-present, Jim Kynde Meyer
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ This plugin for Android Studio and IntelliJ helps you work with the
1010

1111
## Features
1212
- Automatic code generation: models are re-generated whenever GraphQL files change
13-
- Integration with the [GraphQL IntelliJ Plugin](https://plugins.jetbrains.com/plugin/8097-js-graphql): the structure of the Apollo project is automatically contributed, so there is no need to create a `graphql.config.yml` / `.graphqlconfig` file
1413
- Navigation Kotlin code ⇄ GraphQL definitions
1514
- Unused operations and fields highlighting
1615
- Normalized cache viewer
@@ -52,3 +51,7 @@ Repositories</kbd> > <kbd>+</kbd> > <kbd>https://go.apollo.dev/ij-plugin-snapsho
5251
<img src="assets/instructions-2-add-repository.png" width="600" />
5352

5453
Then search for "Apollo GraphQL" and install the plugin as usual.
54+
55+
## Acknowledgements
56+
57+
This plugin incorporates code from the [JetBrains GraphQL plugin](https://github.com/JetBrains/js-graphql-intellij-plugin).

gradle.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION_NAME=4.3.2-SNAPSHOT
1+
VERSION_NAME=5.0.0-SNAPSHOT
22

33
org.gradle.jvmargs=-Xmx8g
44

@@ -11,3 +11,5 @@ org.gradle.parallel=true
1111
# suppress inspection "UnusedProperty"
1212
kotlin.stdlib.default.dependency=false
1313

14+
# See https://platform.jetbrains.com/t/new-intellijplatformresolver-helper-to-control-the-intellij-platform-gradle-plugin-dependency-extraction/2024/4
15+
org.jetbrains.intellij.platform.intellijPlatformIdesCache=~/.intellijPlatform/ides/

gradle/libs.versions.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
kotlin-plugin = "2.1.21"
3-
intellij-platform-plugin = "2.7.0"
4-
apollo = "4.3.1"
3+
intellij-platform-plugin = "2.8.0"
4+
apollo = "5.0.0-alpha.2"
55
grammarkit-plugin = "2022.3.2.2"
66
changelog-plugin = "2.2.1"
77
sqlite-jdbc = "3.43.2.0"
@@ -32,9 +32,10 @@ changelog = { id = "org.jetbrains.changelog", version.ref = "changelog-plugin" }
3232
apollo-annotations = { group = "com.apollographql.apollo", name = "apollo-annotations", version.ref = "apollo" }
3333
apollo-api = { group = "com.apollographql.apollo", name = "apollo-api", version.ref = "apollo" }
3434
apollo-runtime = { group = "com.apollographql.apollo", name = "apollo-runtime", version.ref = "apollo" }
35-
apollo-gradle-plugin-external = { group = "com.apollographql.apollo", name = "apollo-gradle-plugin-external", version.ref = "apollo" }
35+
apollo-gradle-plugin = { group = "com.apollographql.apollo", name = "apollo-gradle-plugin", version.ref = "apollo" }
3636
apollo-ast = { group = "com.apollographql.apollo", name = "apollo-ast", version.ref = "apollo" }
3737
apollo-tooling = { group = "com.apollographql.apollo", name = "apollo-tooling", version.ref = "apollo" }
38+
apollo-compiler = { group = "com.apollographql.apollo", name = "apollo-compiler", version.ref = "apollo" }
3839
apollo-normalized-cache-sqlite-classic = { group = "com.apollographql.apollo", name = "apollo-normalized-cache-sqlite", version.ref = "apollo" }
3940
apollo-normalized-cache-sqlite-new = { group = "com.apollographql.cache", name = "normalized-cache-sqlite", version.ref = "apollo-normalizedcache" }
4041
sqlite-jdbc = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite-jdbc" }

jsgraphql/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ tasks {
4141

4242
dependencies {
4343
intellijPlatform {
44-
intellijIdeaUltimate(libs.versions.intellij.platform.version.get())
44+
intellijIdeaUltimate(libs.versions.intellij.platform.version.get()) {
45+
useCache = true
46+
}
4547
bundledPlugins(
4648
listOf(
4749
"org.jetbrains.kotlin",

plugin/build.gradle.kts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ plugins {
2020
}
2121

2222
repositories {
23-
// mavenLocal()
2423
// maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
2524
// maven("https://storage.googleapis.com/apollo-previews/m2/")
2625
mavenCentral()
26+
// mavenLocal()
2727

2828
intellijPlatform {
2929
defaultRepositories()
@@ -143,7 +143,9 @@ dependencies {
143143
// IntelliJ Platform dependencies must be declared before the intellijPlatform block
144144
// See https://github.com/JetBrains/intellij-platform-gradle-plugin/issues/1784
145145
intellijPlatform {
146-
intellijIdeaUltimate(libs.versions.intellij.platform.version.get())
146+
intellijIdeaUltimate(libs.versions.intellij.platform.version.get()) {
147+
useCache = true
148+
}
147149

148150
// Plugin dependencies
149151
// See https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
@@ -178,7 +180,7 @@ dependencies {
178180

179181
// Coroutines must be excluded to avoid a conflict with the version bundled with the IDE
180182
// See https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#coroutinesLibraries
181-
implementation(libs.apollo.gradle.plugin.external) {
183+
implementation(libs.apollo.gradle.plugin) {
182184
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core")
183185
}
184186
implementation(libs.apollo.ast)
@@ -193,7 +195,10 @@ dependencies {
193195
implementation(libs.apollo.runtime) {
194196
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core")
195197
}
198+
implementation(libs.apollo.compiler)
199+
196200
runtimeOnly(libs.slf4j.simple)
201+
197202
testImplementation(libs.google.testparameterinjector)
198203

199204
// Temporary workaround for https://github.com/JetBrains/intellij-platform-gradle-plugin/issues/1663
@@ -230,7 +235,7 @@ intellijPlatform {
230235
if (isSnapshotBuild()) {
231236
"Weekly snapshot builds contain the latest changes from the <code>main</code> branch."
232237
} else {
233-
"See the <a href=\"https://github.com/apollographql/apollo-kotlin/releases/tag/v${project.version}\">release notes</a>."
238+
"See the <a href=\"https://github.com/apollographql/apollo-intellij-plugin/releases/tag/v${project.version}\">release notes</a>."
234239
}
235240
)
236241
}

plugin/src/main/kotlin/com/apollographql/ijplugin/codegen/ApolloCodegenService.kt

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.apollographql.ijplugin.codegen
33
import com.apollographql.ijplugin.gradle.CODEGEN_GRADLE_TASK_NAME
44
import com.apollographql.ijplugin.gradle.GradleHasSyncedListener
55
import com.apollographql.ijplugin.gradle.SimpleProgressListener
6+
import com.apollographql.ijplugin.gradle.apolloKotlinProjectModelService
67
import com.apollographql.ijplugin.gradle.getGradleRootPath
78
import com.apollographql.ijplugin.gradle.runGradleBuild
89
import com.apollographql.ijplugin.project.ApolloProjectListener
@@ -12,13 +13,15 @@ import com.apollographql.ijplugin.settings.ProjectSettingsListener
1213
import com.apollographql.ijplugin.settings.ProjectSettingsState
1314
import com.apollographql.ijplugin.settings.projectSettingsState
1415
import com.apollographql.ijplugin.util.apolloGeneratedSourcesRoots
16+
import com.apollographql.ijplugin.util.apolloKotlinService
1517
import com.apollographql.ijplugin.util.dispose
1618
import com.apollographql.ijplugin.util.isNotDisposed
1719
import com.apollographql.ijplugin.util.logd
1820
import com.apollographql.ijplugin.util.logw
1921
import com.apollographql.ijplugin.util.newDisposable
2022
import com.apollographql.ijplugin.util.runWriteActionInEdt
2123
import com.intellij.lang.jsgraphql.GraphQLFileType
24+
import com.intellij.lang.jsgraphql.psi.GraphQLFile
2225
import com.intellij.openapi.Disposable
2326
import com.intellij.openapi.components.Service
2427
import com.intellij.openapi.editor.Document
@@ -33,6 +36,7 @@ import com.intellij.openapi.project.Project
3336
import com.intellij.openapi.roots.ProjectRootManager
3437
import com.intellij.openapi.util.CheckedDisposable
3538
import com.intellij.openapi.vfs.VfsUtil
39+
import com.intellij.psi.PsiDocumentManager
3640
import kotlinx.coroutines.CoroutineScope
3741
import kotlinx.coroutines.launch
3842
import org.gradle.tooling.CancellationTokenSource
@@ -83,20 +87,19 @@ class ApolloCodegenService(
8387

8488
private fun startOrStopCodegenObservers() {
8589
if (shouldTriggerCodegenAutomatically()) {
86-
// To make the codegen more reactive, any touched GraphQL document will automatically be saved (thus triggering Gradle)
90+
// To make the codegen more reactive, any touched GraphQL document will automatically be saved (thus triggering the codegen)
8791
// as soon as the current editor is changed.
8892
startObserveDocumentChanges()
8993
startObserveFileEditorChanges()
9094

91-
startContinuousGradleCodegen()
95+
startCodegen()
9296

93-
// Since we rely on Gradle's continuous build, which is not re-triggered when Gradle build files change, observe that
94-
// ourselves and restart the build when it happens.
97+
// A Gradle sync is a good indicator that Gradle files have changed - trigger a codegen build when that happens.
9598
startObserveGradleHasSynced()
9699
} else {
97100
stopObserveDocumentChanges()
98101
stopObserveFileEditorChanges()
99-
stopContinuousGradleCodegen()
102+
stopCodegen()
100103
stopObserveGradleHasSynced()
101104
}
102105
}
@@ -144,8 +147,11 @@ class ApolloCodegenService(
144147
fileEditorChangesDisposable = disposable
145148
project.messageBus.connect(disposable).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener {
146149
override fun selectionChanged(event: FileEditorManagerEvent) {
147-
logd(event.newFile)
150+
logd(event.newFile?.path)
148151
dirtyGqlDocument?.let {
152+
val operationGraphQLFile = PsiDocumentManager.getInstance(project).getPsiFile(dirtyGqlDocument!!) as? GraphQLFile
153+
val apolloKotlinService = operationGraphQLFile?.apolloKotlinService()
154+
logd("apolloKotlinService=${apolloKotlinService?.id}")
149155
dirtyGqlDocument = null
150156
runWriteActionInEdt {
151157
try {
@@ -156,6 +162,14 @@ class ApolloCodegenService(
156162
logw(e, "Failed to save document")
157163
}
158164
}
165+
166+
if (apolloKotlinService?.hasCompilerOptions == true) {
167+
// We can use the built-in Apollo compiler
168+
ApolloCompilerHelper(project).generateSources(apolloKotlinService)
169+
} else {
170+
// Fall back to the Gradle codegen task
171+
startGradleCodegen()
172+
}
159173
}
160174
}
161175
})
@@ -167,7 +181,7 @@ class ApolloCodegenService(
167181
fileEditorChangesDisposable = null
168182
}
169183

170-
private fun startContinuousGradleCodegen() {
184+
private fun startGradleCodegen() {
171185
logd()
172186

173187
if (gradleCodegenCancellation != null) {
@@ -178,18 +192,17 @@ class ApolloCodegenService(
178192
val modules = ModuleManager.getInstance(project).modules
179193
coroutineScope.launch {
180194
gradleCodegenCancellation = GradleConnector.newCancellationTokenSource()
181-
logd("Start Gradle")
195+
logd("Start Gradle codegen build")
182196
try {
183197
val cancellationToken = gradleCodegenCancellation!!.token()
184198
val gradleProjectPath = project.getGradleRootPath()
185199
if (gradleProjectPath == null) {
186200
logw("Could not get Gradle root project path")
187201
return@launch
188202
}
189-
runGradleBuild(project, gradleProjectPath) {
190-
it.forTasks(CODEGEN_GRADLE_TASK_NAME)
203+
runGradleBuild(project, gradleProjectPath) { buildLauncher ->
204+
buildLauncher.forTasks(CODEGEN_GRADLE_TASK_NAME)
191205
.withCancellationToken(cancellationToken)
192-
.addArguments("--continuous")
193206
.let {
194207
if (project.projectSettingsState.automaticCodegenAdditionalGradleJvmArguments.isNotEmpty()) {
195208
it.addJvmArguments(project.projectSettingsState.automaticCodegenAdditionalGradleJvmArguments.split(' '))
@@ -199,24 +212,24 @@ class ApolloCodegenService(
199212
}
200213
.addProgressListener(object : SimpleProgressListener() {
201214
override fun onSuccess() {
202-
logd("Gradle build success, marking generated source roots as dirty")
215+
logd("Gradle codegen build success, marking generated source roots as dirty")
203216
// Mark the generated sources dirty so the files are visible to the IDE
204217
val generatedSourceRoots = modules.flatMap { it.apolloGeneratedSourcesRoots() }
205218
logd("Mark dirty $generatedSourceRoots")
206219
VfsUtil.markDirtyAndRefresh(true, true, true, *generatedSourceRoots.toTypedArray())
207220
}
208221
})
209222
}
210-
logd("Gradle execution finished")
223+
logd("Gradle codegen build finished")
211224
} catch (t: Throwable) {
212-
logd(t, "Gradle execution failed")
225+
logd(t, "Gradle codegen build failed")
213226
} finally {
214227
gradleCodegenCancellation = null
215228
}
216229
}
217230
}
218231

219-
private fun stopContinuousGradleCodegen() {
232+
private fun stopCodegen() {
220233
logd()
221234
gradleCodegenCancellation?.cancel()
222235
gradleCodegenCancellation = null
@@ -235,12 +248,22 @@ class ApolloCodegenService(
235248
project.messageBus.connect(disposable).subscribe(GradleHasSyncedListener.TOPIC, object : GradleHasSyncedListener {
236249
override fun gradleHasSynced() {
237250
logd()
238-
stopContinuousGradleCodegen()
239-
if (shouldTriggerCodegenAutomatically()) startContinuousGradleCodegen()
251+
stopCodegen()
252+
if (shouldTriggerCodegenAutomatically()) startCodegen()
240253
}
241254
})
242255
}
243256

257+
private fun startCodegen() {
258+
if (project.apolloKotlinProjectModelService.getApolloKotlinServices().any { it.hasCompilerOptions }) {
259+
logd("Using Apollo compiler for codegen")
260+
ApolloCompilerHelper(project).generateAllSources()
261+
} else {
262+
logd("Using Gradle codegen task")
263+
startGradleCodegen()
264+
}
265+
}
266+
244267
private fun stopObserveGradleHasSynced() {
245268
logd()
246269
dispose(gradleHasSyncedDisposable)
@@ -249,6 +272,6 @@ class ApolloCodegenService(
249272

250273
override fun dispose() {
251274
logd("project=${project.name}")
252-
stopContinuousGradleCodegen()
275+
stopCodegen()
253276
}
254277
}

0 commit comments

Comments
 (0)