Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IJ plugin] 'Expensive field' inspection #5050

Merged
merged 4 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/libraries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ gradle-japicmp-plugin = { group = "me.champeau.gradle", name = "japicmp-gradle-p
gradle-publish-plugin = { group = "com.gradle.publish", name = "plugin-publish-plugin", version = "1.1.0" }
graphqlkotlin = { group = "com.expediagroup", name = "graphql-kotlin-spring-server", version = "5.3.0" }
guava-jre = { group = "com.google.guava", name = "guava", version.ref = "guava" }
intellij-plugin = "org.jetbrains.intellij.plugins:gradle-intellij-plugin:1.14.0"
intellij-plugin = "org.jetbrains.intellij.plugins:gradle-intellij-plugin:1.14.2"
intellij-changelog = "org.jetbrains.intellij.plugins:gradle-changelog-plugin:2.0.0"
jetbrains-annotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrains-annotations" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
Expand Down
1 change: 1 addition & 0 deletions intellij-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ publishing {

dependencies {
implementation(project(":apollo-gradle-plugin-external"))
implementation(project(":apollo-tooling"))
}

fun isSnapshotBuild() = System.getenv("COM_APOLLOGRAPHQL_IJ_PLUGIN_SNAPSHOT").toBoolean()
2 changes: 1 addition & 1 deletion intellij-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ platformVersion=222.3739.54
# To find the version of a plugin relative to the platoform version, see the plugin's page on the Marketplace,
# e.g. for the toml plugin: https://plugins.jetbrains.com/plugin/8195-toml/versions/stable
# Note: jsgraphql has 2 published versions: one with `pluginSinceBuild` set to latest, and one set to an older (more broadly available) version.
platformPlugins=com.intellij.java, org.jetbrains.kotlin, com.intellij.gradle, com.intellij.lang.jsgraphql:4.0.0-222, org.toml.lang:222.3739.16
platformPlugins=com.intellij.java, org.jetbrains.kotlin, com.intellij.gradle, com.intellij.lang.jsgraphql:4.0.1-222, org.toml.lang:222.3739.16

# JVM language level used to build project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+.
javaVersion=17
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.apollographql.ijplugin.gradle

import com.intellij.util.messages.Topic

interface ApolloKotlinServiceListener {
companion object {
@Topic.ProjectLevel
val TOPIC: Topic<ApolloKotlinServiceListener> = Topic.create("ApolloKotlinServices are available", ApolloKotlinServiceListener::class.java)
}

fun apolloKotlinServicesAvailable()
}

data class ApolloKotlinService(
val gradleProjectName: String,
val serviceName: String,
val schemaPaths: List<String>,
val operationPaths: List<String>,
val endpointUrl: String?,
val endpointHeaders: Map<String, String>?,
) {
data class Id(val gradleProjectName: String, val serviceName: String) {
override fun toString() = "$gradleProjectName/$serviceName"

companion object {
fun fromString(string: String): Id? {
val split = string.split("/")
if (split.size != 2) return null
return Id(split[0], split[1])
}
}
}

val id = Id(gradleProjectName, serviceName)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package com.apollographql.ijplugin.gradle

import com.apollographql.apollo3.gradle.api.ApolloGradleToolingModel
import com.apollographql.ijplugin.ApolloBundle
import com.apollographql.ijplugin.graphql.GraphQLProjectFiles
import com.apollographql.ijplugin.graphql.GraphQLProjectFilesListener
import com.apollographql.ijplugin.project.ApolloProjectListener
import com.apollographql.ijplugin.project.apolloProjectService
import com.apollographql.ijplugin.settings.SettingsListener
Expand All @@ -15,6 +13,7 @@ import com.apollographql.ijplugin.util.logd
import com.apollographql.ijplugin.util.logw
import com.apollographql.ijplugin.util.newDisposable
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.service
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
Expand Down Expand Up @@ -44,7 +43,7 @@ class GradleToolingModelService(

private var fetchToolingModelsTask: FetchToolingModelsTask? = null

var graphQLProjectFiles: List<GraphQLProjectFiles> = emptyList()
var apolloKotlinServices: List<ApolloKotlinService> = emptyList()

init {
logd("project=${project.name}")
Expand Down Expand Up @@ -102,9 +101,15 @@ class GradleToolingModelService(
private fun startObservingSettings() {
logd()
project.messageBus.connect(this).subscribe(SettingsListener.TOPIC, object : SettingsListener {
private var contributeConfigurationToGraphqlPlugin: Boolean = project.settingsState.contributeConfigurationToGraphqlPlugin

override fun settingsChanged(settingsState: SettingsState) {
logd("settingsState=$settingsState")
startOrAbortFetchToolingModels()
val contributeConfigurationToGraphqlPluginChanged = contributeConfigurationToGraphqlPlugin != settingsState.contributeConfigurationToGraphqlPlugin
contributeConfigurationToGraphqlPlugin = settingsState.contributeConfigurationToGraphqlPlugin
logd("contributeConfigurationToGraphqlPluginChanged=$contributeConfigurationToGraphqlPluginChanged")
if (contributeConfigurationToGraphqlPluginChanged) {
startOrAbortFetchToolingModels()
}
}
})
}
Expand Down Expand Up @@ -163,7 +168,7 @@ class GradleToolingModelService(
logd("allApolloGradleProjects=${allApolloGradleProjects.map { it.name }}")
indicator.isIndeterminate = false
val allToolingModels = allApolloGradleProjects.mapIndexedNotNull { index, gradleProject ->
if (isAbortRequested()) return@run
if (isAbortRequested()) return@run
indicator.fraction = (index + 1).toDouble() / allApolloGradleProjects.size
gradleExecutionHelper.execute(gradleProject.projectDirectory.canonicalPath, executionSettings) { connection ->
gradleCancellation = GradleConnector.newCancellationTokenSource()
Expand Down Expand Up @@ -191,7 +196,7 @@ class GradleToolingModelService(

logd("allToolingModels=$allToolingModels")
if (isAbortRequested()) return
computeGraphQLProjectFiles(allToolingModels)
computeApolloKotlinServices(allToolingModels)
}

private fun isAbortRequested(): Boolean {
Expand All @@ -218,21 +223,22 @@ class GradleToolingModelService(
}
}

private fun computeGraphQLProjectFiles(toolingModels: List<ApolloGradleToolingModel>) {
// Compute the GraphQLProjectFiles, taking into account the dependencies between projects
private fun computeApolloKotlinServices(toolingModels: List<ApolloGradleToolingModel>) {
// Compute the ApolloKotlinServices, taking into account the dependencies between projects
val allKnownProjectNames = toolingModels.map { it.projectName }
val projectServiceToGraphQLProjectFiles = mutableMapOf<String, GraphQLProjectFiles>()
fun getGraphQLProjectFiles(projectName: String, serviceName: String): GraphQLProjectFiles {
val projectServiceToApolloKotlinServices = mutableMapOf<String, ApolloKotlinService>()
fun getApolloKotlinService(projectName: String, serviceName: String): ApolloKotlinService {
val key = "$projectName/$serviceName"
return projectServiceToGraphQLProjectFiles.getOrPut(key) {
return projectServiceToApolloKotlinServices.getOrPut(key) {
val toolingModel = toolingModels.first { it.projectName == projectName }
val serviceInfo = toolingModel.serviceInfos.first { it.name == serviceName }
val dependenciesProjectFiles = serviceInfo.upstreamProjects
// The tooling model for some upstream projects might not have been fetched successfully - filter them out
.filter { upstreamProject -> upstreamProject in allKnownProjectNames }
.map { getGraphQLProjectFiles(it, serviceName) }
GraphQLProjectFiles(
name = key,
.map { getApolloKotlinService(it, serviceName) }
ApolloKotlinService(
gradleProjectName = projectName,
serviceName = serviceName,
schemaPaths = (serviceInfo.schemaFiles.mapNotNull { it.toProjectLocalPathOrNull() } +
dependenciesProjectFiles.flatMap { it.schemaPaths })
.distinct(),
Expand All @@ -245,17 +251,17 @@ class GradleToolingModelService(
}
}

val graphQLProjectFiles = mutableListOf<GraphQLProjectFiles>()
val apolloKotlinServices = mutableListOf<ApolloKotlinService>()
for (toolingModel in toolingModels) {
for (serviceInfo in toolingModel.serviceInfos) {
graphQLProjectFiles += getGraphQLProjectFiles(toolingModel.projectName, serviceInfo.name)
apolloKotlinServices += getApolloKotlinService(toolingModel.projectName, serviceInfo.name)
}
}
this.graphQLProjectFiles = graphQLProjectFiles
logd("graphQLProjectFiles=$graphQLProjectFiles")
this.apolloKotlinServices = apolloKotlinServices
logd("apolloKotlinServices=$apolloKotlinServices")

// Project files are available, notify interested parties
project.messageBus.syncPublisher(GraphQLProjectFilesListener.TOPIC).projectFilesAvailable()
project.messageBus.syncPublisher(ApolloKotlinServiceListener.TOPIC).apolloKotlinServicesAvailable()
}

private fun File.toProjectLocalPathOrNull(): String? {
Expand All @@ -275,4 +281,11 @@ class GradleToolingModelService(
logd("project=${project.name}")
abortFetchToolingModels()
}

companion object {
fun getApolloKotlinServices(project: Project): List<ApolloKotlinService> {
if (!project.apolloProjectService.isInitialized) return emptyList()
return project.service<GradleToolingModelService>().apolloKotlinServices
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.apollographql.ijplugin.graphql

import com.apollographql.ijplugin.gradle.ApolloKotlinService
import com.apollographql.ijplugin.gradle.GradleToolingModelService
import com.apollographql.ijplugin.project.apolloProjectService
import com.apollographql.ijplugin.util.logd
Expand All @@ -25,21 +26,21 @@ class ApolloGraphQLConfigContributor : GraphQLConfigContributor {
dir = projectDir,
file = null,
rawData = GraphQLRawConfig(
projects = project.service<GradleToolingModelService>().graphQLProjectFiles.map { graphQLProjectFiles ->
graphQLProjectFiles.name to graphQLProjectFiles.toGraphQLRawProjectConfig()
projects = project.service<GradleToolingModelService>().apolloKotlinServices.map { apolloKotlinService ->
apolloKotlinService.id.toString() to apolloKotlinService.toGraphQLRawProjectConfig()
}.toMap()
)
)
)
}

private fun GraphQLProjectFiles.toGraphQLRawProjectConfig() = GraphQLRawProjectConfig(
private fun ApolloKotlinService.toGraphQLRawProjectConfig() = GraphQLRawProjectConfig(
schema = schemaPaths.map { GraphQLRawSchemaPointer(it) },
include = operationPaths.map { "$it/*.graphql" },
extensions = endpointUrl?.let {
mapOf(
GraphQLConfigKeys.EXTENSION_ENDPOINTS to mapOf(
name to buildMap {
serviceName to buildMap {
put(GraphQLConfigKeys.EXTENSION_ENDPOINT_URL, endpointUrl)
if (endpointHeaders != null) {
put(GraphQLConfigKeys.HEADERS, endpointHeaders)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.apollographql.ijplugin.graphql

import com.apollographql.ijplugin.gradle.ApolloKotlinServiceListener
import com.apollographql.ijplugin.util.logd
import com.intellij.lang.jsgraphql.ide.config.GraphQLConfigProvider
import com.intellij.openapi.Disposable
Expand All @@ -11,8 +12,8 @@ class GraphQLConfigService(
) : Disposable {
init {
logd("project=${project.name}")
project.messageBus.connect(this).subscribe(GraphQLProjectFilesListener.TOPIC, object : GraphQLProjectFilesListener {
override fun projectFilesAvailable() {
project.messageBus.connect(this).subscribe(ApolloKotlinServiceListener.TOPIC, object : ApolloKotlinServiceListener {
override fun apolloKotlinServicesAvailable() {
logd("Calling scheduleConfigurationReload")
project.service<GraphQLConfigProvider>().scheduleConfigurationReload()
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.apollographql.ijplugin.codegen.ApolloCodegenService
import com.apollographql.ijplugin.gradle.GradleToolingModelService
import com.apollographql.ijplugin.graphql.GraphQLConfigService
import com.apollographql.ijplugin.settings.SettingsService
import com.apollographql.ijplugin.studio.fieldinsights.FieldInsightsService
import com.apollographql.ijplugin.studio.sandbox.SandboxService
import com.apollographql.ijplugin.util.logd
import com.intellij.openapi.components.service
Expand All @@ -24,6 +25,7 @@ internal class ApolloProjectManagerListener : ProjectManagerListener {
project.service<SettingsService>()
project.service<GraphQLConfigService>()
project.service<SandboxService>()
project.service<FieldInsightsService>()

project.apolloProjectService.isInitialized = true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.apollographql.ijplugin.settings

import com.apollographql.ijplugin.ApolloBundle
import com.apollographql.ijplugin.settings.studio.ApiKeyDialog
import com.intellij.openapi.project.Project
import com.intellij.ui.AddEditRemovePanel
import com.intellij.ui.dsl.builder.panel
import com.intellij.ui.dsl.gridLayout.HorizontalAlign
import javax.swing.JCheckBox
import javax.swing.JComponent
import javax.swing.JPanel

class SettingsComponent {

class SettingsComponent(private val project: Project) {
private lateinit var chkAutomaticCodegenTriggering: JCheckBox
private lateinit var chkContributeConfigurationToGraphqlPlugin: JCheckBox
private lateinit var addEditRemovePanel: AddEditRemovePanel<ApolloKotlinServiceConfiguration>

val panel: JPanel = panel {
group(ApolloBundle.message("settings.codegen.title")) {
Expand All @@ -25,6 +31,54 @@ class SettingsComponent {
.component
}
}
group(ApolloBundle.message("settings.studio.title")) {
row {
addEditRemovePanel = object : AddEditRemovePanel<ApolloKotlinServiceConfiguration>(
ApiKeysModel(),
emptyList(),
ApolloBundle.message("settings.studio.apiKeys.text")
) {
override fun addItem(): ApolloKotlinServiceConfiguration? {
val apiKeyDialog = ApiKeyDialog(project)
if (!apiKeyDialog.showAndGet()) return null
return ApolloKotlinServiceConfiguration(
id = apiKeyDialog.apolloKotlinServiceId,
graphOsGraphName = apiKeyDialog.graphOsServiceName,
).apply {
graphOsApiKey = apiKeyDialog.graphOsApiKey
}
}

override fun editItem(o: ApolloKotlinServiceConfiguration): ApolloKotlinServiceConfiguration? {
val apiKeyDialog = ApiKeyDialog(
project,
apolloKotlinServiceId = o.apolloKotlinServiceId,
graphOsApiKey = o.graphOsApiKey ?: "",
graphOsServiceName = o.graphOsGraphName
)
if (!apiKeyDialog.showAndGet()) return null
return ApolloKotlinServiceConfiguration(
id = apiKeyDialog.apolloKotlinServiceId,
graphOsGraphName = apiKeyDialog.graphOsServiceName,
).apply {
graphOsApiKey = apiKeyDialog.graphOsApiKey
}
}

override fun removeItem(o: ApolloKotlinServiceConfiguration?): Boolean {
return true
}
}.apply {
table.setShowGrid(false)
table.setShowColumns(true)
emptyText.text = ApolloBundle.message("settings.studio.apiKeys.empty")
}

cell(addEditRemovePanel)
.horizontalAlign(HorizontalAlign.FILL)
.comment(ApolloBundle.message("settings.studio.apiKeys.comment"))
}
}
}

val preferredFocusedComponent: JComponent = chkAutomaticCodegenTriggering
Expand All @@ -40,4 +94,30 @@ class SettingsComponent {
set(value) {
chkContributeConfigurationToGraphqlPlugin.isSelected = value
}

var apolloKotlinServiceConfigurations: List<ApolloKotlinServiceConfiguration>
get() = addEditRemovePanel.data.toList()
set(value) {
addEditRemovePanel.data = value.toMutableList()
}
}

class ApiKeysModel : AddEditRemovePanel.TableModel<ApolloKotlinServiceConfiguration>() {
override fun getColumnCount() = 4

override fun getColumnName(columnIndex: Int) = when (columnIndex) {
0 -> ApolloBundle.message("settings.studio.apiKeys.table.columnGradleProjectName")
1 -> ApolloBundle.message("settings.studio.apiKeys.table.columnApolloKotlinServiceName")
2 -> ApolloBundle.message("settings.studio.apiKeys.table.columnGraphOsApiKey")
3 -> ApolloBundle.message("settings.studio.apiKeys.table.columnGraphOsGraphName")
else -> throw IllegalArgumentException()
}

override fun getField(o: ApolloKotlinServiceConfiguration, columnIndex: Int) = when (columnIndex) {
0 -> o.apolloKotlinServiceId.gradleProjectName
1 -> o.apolloKotlinServiceId.serviceName
2 -> "••••••••"
3 -> o.graphOsGraphName
else -> throw IllegalArgumentException()
}
}
Loading