Skip to content

Commit 09b851f

Browse files
feat(amazonq): add q config to lsp/configuration (#5520)
1 parent 57edb41 commit 09b851f

File tree

18 files changed

+246
-160
lines changed

18 files changed

+246
-160
lines changed

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.GetCodeFixJobR
2222
import software.amazon.awssdk.services.codewhispererruntime.model.GetTestGenerationResponse
2323
import software.amazon.awssdk.services.codewhispererruntime.model.IdeCategory
2424
import software.amazon.awssdk.services.codewhispererruntime.model.InlineChatUserDecision
25-
import software.amazon.awssdk.services.codewhispererruntime.model.ListAvailableCustomizationsRequest
2625
import software.amazon.awssdk.services.codewhispererruntime.model.ListCodeAnalysisFindingsRequest
2726
import software.amazon.awssdk.services.codewhispererruntime.model.ListCodeAnalysisFindingsResponse
2827
import software.amazon.awssdk.services.codewhispererruntime.model.ListFeatureEvaluationsResponse
@@ -35,8 +34,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.StartTestGener
3534
import software.amazon.awssdk.services.codewhispererruntime.model.SuggestionState
3635
import software.amazon.awssdk.services.codewhispererruntime.model.TargetCode
3736
import software.amazon.awssdk.services.codewhispererruntime.model.UserIntent
38-
import software.aws.toolkits.core.utils.debug
39-
import software.aws.toolkits.core.utils.getLogger
4037
import software.aws.toolkits.jetbrains.services.amazonq.codeWhispererUserContext
4138
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
4239
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization
@@ -78,8 +75,6 @@ interface CodeWhispererClientAdaptor {
7875

7976
fun getCodeFixJob(request: GetCodeFixJobRequest): GetCodeFixJobResponse
8077

81-
fun listAvailableCustomizations(): List<CodeWhispererCustomization>
82-
8378
fun startTestGeneration(uploadId: String, targetCode: List<TargetCode>, userInput: String): StartTestGenerationResponse
8479

8580
fun getTestGeneration(jobId: String, jobGroupName: String): GetTestGenerationResponse
@@ -281,28 +276,6 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW
281276

282277
override fun getCodeFixJob(request: GetCodeFixJobRequest): GetCodeFixJobResponse = bearerClient().getCodeFixJob(request)
283278

284-
// DO NOT directly use this method to fetch customizations, use wrapper [CodeWhispererModelConfigurator.listCustomization()] instead
285-
override fun listAvailableCustomizations(): List<CodeWhispererCustomization> =
286-
bearerClient().listAvailableCustomizationsPaginator(
287-
ListAvailableCustomizationsRequest.builder().profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn).build()
288-
)
289-
.stream()
290-
.toList()
291-
.flatMap { resp ->
292-
LOG.debug {
293-
"listAvailableCustomizations: requestId: ${resp.responseMetadata().requestId()}, customizations: ${
294-
resp.customizations().map { it.name() }
295-
}"
296-
}
297-
resp.customizations().map {
298-
CodeWhispererCustomization(
299-
arn = it.arn(),
300-
name = it.name(),
301-
description = it.description()
302-
)
303-
}
304-
}
305-
306279
override fun startTestGeneration(uploadId: String, targetCode: List<TargetCode>, userInput: String): StartTestGenerationResponse =
307280
bearerClient().startTestGeneration { builder ->
308281
builder.uploadId(uploadId)
@@ -799,10 +772,6 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW
799772
requestBuilder.userContext(codeWhispererUserContext())
800773
requestBuilder.profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn)
801774
}
802-
803-
companion object {
804-
private val LOG = getLogger<CodeWhispererClientAdaptorImpl>()
805-
}
806775
}
807776

808777
private fun CodewhispererSuggestionState.toCodeWhispererSdkType() = when {

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhisperer
8686
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.getTelemetryOptOutPreference
8787
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.notifyErrorCodeWhispererUsageLimit
8888
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.promptReAuth
89+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CustomizationConstants
8990
import software.aws.toolkits.jetbrains.services.codewhisperer.util.FileContextProvider
9091
import software.aws.toolkits.jetbrains.settings.CodeWhispererSettings
9192
import software.aws.toolkits.jetbrains.utils.isInjectedText
@@ -333,7 +334,7 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
333334
val displayMessage: String
334335

335336
if (
336-
CodeWhispererConstants.Customization.invalidCustomizationExceptionPredicate(e) ||
337+
CustomizationConstants.invalidCustomizationExceptionPredicate(e) ||
337338
e is ResourceNotFoundException
338339
) {
339340
(e as CodeWhispererRuntimeException)

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererServiceNew.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhisperer
8383
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.getTelemetryOptOutPreference
8484
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.notifyErrorCodeWhispererUsageLimit
8585
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.promptReAuth
86+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CustomizationConstants
8687
import software.aws.toolkits.jetbrains.services.codewhisperer.util.FileContextProvider
8788
import software.aws.toolkits.jetbrains.settings.CodeWhispererSettings
8889
import software.aws.toolkits.jetbrains.utils.isInjectedText
@@ -360,7 +361,7 @@ class CodeWhispererServiceNew(private val cs: CoroutineScope) : Disposable {
360361
val displayMessage: String
361362

362363
if (
363-
CodeWhispererConstants.Customization.invalidCustomizationExceptionPredicate(e) ||
364+
CustomizationConstants.invalidCustomizationExceptionPredicate(e) ||
364365
e is ResourceNotFoundException
365366
) {
366367
(e as CodeWhispererRuntimeException)

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererConfigurable.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.intellij.openapi.options.Configurable
1111
import com.intellij.openapi.options.SearchableConfigurable
1212
import com.intellij.openapi.options.ex.Settings
1313
import com.intellij.openapi.project.Project
14+
import com.intellij.openapi.project.ProjectManager
1415
import com.intellij.openapi.ui.emptyText
1516
import com.intellij.ui.components.ActionLink
1617
import com.intellij.ui.components.fields.ExpandableTextField
@@ -23,6 +24,7 @@ import com.intellij.util.concurrency.EdtExecutorService
2324
import com.intellij.util.execution.ParametersListUtil
2425
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
2526
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManagerListener
27+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
2628
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererLoginType
2729
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager
2830
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.isCodeWhispererEnabled
@@ -284,6 +286,20 @@ class CodeWhispererConfigurable(private val project: Project) :
284286
}
285287
}
286288
}
289+
}.also {
290+
val newCallbacks = it.applyCallbacks.toMutableMap()
291+
.also { map ->
292+
val list = map.getOrPut(null) { mutableListOf() } as MutableList<() -> Unit>
293+
list.add {
294+
ProjectManager.getInstance().openProjects.forEach { project ->
295+
if (project.isDisposed) {
296+
return@forEach
297+
}
298+
AmazonQLspService.didChangeConfiguration(project)
299+
}
300+
}
301+
}
302+
it.applyCallbacks = newCallbacks
287303
}
288304

289305
companion object {

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import com.intellij.openapi.editor.markup.EffectType
88
import com.intellij.openapi.editor.markup.TextAttributes
99
import com.intellij.ui.JBColor
1010
import software.amazon.awssdk.regions.Region
11-
import software.amazon.awssdk.services.codewhispererruntime.model.AccessDeniedException
12-
import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException
1311
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeScanResponse
1412
import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererJava
1513
import software.aws.toolkits.telemetry.CodewhispererGettingStartedTask
@@ -59,7 +57,6 @@ object CodeWhispererConstants {
5957
val scanResultsKey = DataKey.create<CodeScanResponse>("amazonq.codescan.result")
6058
val scanScopeKey = DataKey.create<CodeAnalysisScope>("amazonq.codescan.scope")
6159

62-
const val Q_CUSTOM_LEARN_MORE_URI = "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/customizations.html"
6360
const val Q_SUPPORTED_LANG_URI = "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/q-language-ide-support.html"
6461
const val CODEWHISPERER_CODE_SCAN_LEARN_MORE_URI = "https://docs.aws.amazon.com/codewhisperer/latest/userguide/security-scans.html"
6562
const val CODEWHISPERER_ONBOARDING_DOCUMENTATION_URI = "https://docs.aws.amazon.com/codewhisperer/latest/userguide/features.html"
@@ -157,27 +154,6 @@ object CodeWhispererConstants {
157154
val Sigv4ClientRegion = Region.US_EAST_1
158155
}
159156

160-
object Customization {
161-
private const val noAccessToCustomizationMessage = "Your account is not authorized to use CodeWhisperer Enterprise."
162-
private const val invalidCustomizationMessage = "You are not authorized to access"
163-
164-
val noAccessToCustomizationExceptionPredicate: (e: Exception) -> Boolean = { e ->
165-
if (e !is CodeWhispererRuntimeException) {
166-
false
167-
} else {
168-
e is AccessDeniedException && (e.message?.contains(noAccessToCustomizationMessage, ignoreCase = true) ?: false)
169-
}
170-
}
171-
172-
val invalidCustomizationExceptionPredicate: (e: Exception) -> Boolean = { e ->
173-
if (e !is CodeWhispererRuntimeException) {
174-
false
175-
} else {
176-
e is AccessDeniedException && (e.message?.contains(invalidCustomizationMessage, ignoreCase = true) ?: false)
177-
}
178-
}
179-
}
180-
181157
object CrossFile {
182158
const val CHUNK_SIZE = 60
183159
const val NUMBER_OF_LINE_IN_CHUNK = 50

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererClientAdaptorTest.kt

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,10 @@ import software.amazon.awssdk.services.codewhispererruntime.model.CodeAnalysisSt
3131
import software.amazon.awssdk.services.codewhispererruntime.model.CompletionType
3232
import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlRequest
3333
import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlResponse
34-
import software.amazon.awssdk.services.codewhispererruntime.model.Customization
3534
import software.amazon.awssdk.services.codewhispererruntime.model.GenerateCompletionsRequest
3635
import software.amazon.awssdk.services.codewhispererruntime.model.GetCodeAnalysisRequest
3736
import software.amazon.awssdk.services.codewhispererruntime.model.GetCodeAnalysisResponse
3837
import software.amazon.awssdk.services.codewhispererruntime.model.IdeCategory
39-
import software.amazon.awssdk.services.codewhispererruntime.model.ListAvailableCustomizationsRequest
40-
import software.amazon.awssdk.services.codewhispererruntime.model.ListAvailableCustomizationsResponse
4138
import software.amazon.awssdk.services.codewhispererruntime.model.ListCodeAnalysisFindingsRequest
4239
import software.amazon.awssdk.services.codewhispererruntime.model.ListCodeAnalysisFindingsResponse
4340
import software.amazon.awssdk.services.codewhispererruntime.model.ListFeatureEvaluationsRequest
@@ -51,7 +48,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.StartCodeAnaly
5148
import software.amazon.awssdk.services.codewhispererruntime.model.StartCodeAnalysisResponse
5249
import software.amazon.awssdk.services.codewhispererruntime.model.SuggestionState
5350
import software.amazon.awssdk.services.codewhispererruntime.paginators.GenerateCompletionsIterable
54-
import software.amazon.awssdk.services.codewhispererruntime.paginators.ListAvailableCustomizationsIterable
5551
import software.amazon.awssdk.services.ssooidc.SsoOidcClient
5652
import software.aws.toolkits.core.utils.test.aString
5753
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
@@ -158,48 +154,6 @@ class CodeWhispererClientAdaptorTest {
158154
.isInstanceOf(CodeWhispererRuntimeClient::class.java)
159155
}
160156

161-
@Test
162-
fun `listCustomizations`() {
163-
val sdkIterable = ListAvailableCustomizationsIterable(bearerClient, ListAvailableCustomizationsRequest.builder().build())
164-
val mockResponse1 = ListAvailableCustomizationsResponse.builder()
165-
.customizations(
166-
listOf(
167-
Customization.builder().name("custom-1").arn("arn-1").build(),
168-
Customization.builder().name("custom-2").arn("arn-2").build()
169-
)
170-
)
171-
.nextToken("token-1")
172-
.responseMetadata(metadata)
173-
.sdkHttpResponse(sdkHttpResponse)
174-
.build() as ListAvailableCustomizationsResponse
175-
176-
val mockResponse2 = ListAvailableCustomizationsResponse.builder()
177-
.customizations(
178-
listOf(
179-
Customization.builder().name("custom-3").arn("arn-3").build(),
180-
)
181-
)
182-
.nextToken("")
183-
.responseMetadata(metadata)
184-
.sdkHttpResponse(sdkHttpResponse)
185-
.build() as ListAvailableCustomizationsResponse
186-
187-
bearerClient.stub { client ->
188-
on { client.listAvailableCustomizations(any<ListAvailableCustomizationsRequest>()) } doReturnConsecutively listOf(mockResponse1, mockResponse2)
189-
on { client.listAvailableCustomizationsPaginator(any<ListAvailableCustomizationsRequest>()) } doReturn sdkIterable
190-
}
191-
192-
val actual = sut.listAvailableCustomizations()
193-
assertThat(actual).hasSize(3)
194-
assertThat(actual).isEqualTo(
195-
listOf(
196-
CodeWhispererCustomization(name = "custom-1", arn = "arn-1"),
197-
CodeWhispererCustomization(name = "custom-2", arn = "arn-2"),
198-
CodeWhispererCustomization(name = "custom-3", arn = "arn-3")
199-
)
200-
)
201-
}
202-
203157
@Test
204158
fun `generateCompletionsPaginator - bearer`() {
205159
val request = pythonRequest

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ class CodeWhispererModelConfiguratorTest {
470470
"</option>" +
471471
"</component>"
472472

473-
assertThat(actual).isEqualTo(expected)
473+
assertThat(actual).isEqualToIgnoringWhitespace(expected)
474474
}
475475

476476
@Test
@@ -574,11 +574,6 @@ class CodeWhispererModelConfiguratorTest {
574574

575575
assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization)
576576

577-
val fakeCustomizations = listOf(
578-
CodeWhispererCustomization("oldArn", "oldName", "oldDescription")
579-
)
580-
mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations }
581-
582577
ApplicationManager.getApplication().messageBus
583578
.syncPublisher(QRegionProfileSelectedListener.TOPIC)
584579
.onProfileSelected(projectRule.project, null)
@@ -593,10 +588,6 @@ class CodeWhispererModelConfiguratorTest {
593588
val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription")
594589
sut.switchCustomization(projectRule.project, oldCustomization)
595590
assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization)
596-
val fakeCustomizations = listOf(
597-
CodeWhispererCustomization("newArn", "newName", "newDescription")
598-
)
599-
mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations }
600591

601592
val latch = CountDownLatch(1)
602593

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererSettingsTest.kt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager
1313
import com.intellij.testFramework.replaceService
1414
import com.intellij.testFramework.runInEdtAndWait
1515
import com.intellij.util.xmlb.XmlSerializer
16-
import io.mockk.every
1716
import io.mockk.junit4.MockKRule
18-
import io.mockk.mockkObject
1917
import org.assertj.core.api.Assertions.assertThat
2018
import org.jdom.output.XMLOutputter
2119
import org.junit.Before
@@ -28,7 +26,6 @@ import org.mockito.kotlin.spy
2826
import org.mockito.kotlin.verify
2927
import org.mockito.kotlin.whenever
3028
import software.aws.toolkits.jetbrains.core.ToolWindowHeadlessManagerImpl
31-
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3229
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererLoginType
3330
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExploreActionState
3431
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.isCodeWhispererEnabled
@@ -254,18 +251,6 @@ class CodeWhispererSettingsTest : CodeWhispererTestBase() {
254251
assertThat(sut.getProjectContextIndexMaxSize()).isEqualTo(expected)
255252
}
256253
}
257-
258-
@Test
259-
fun `toggleMetricOptIn should trigger LSP didChangeConfiguration`() {
260-
mockkObject(AmazonQLspService)
261-
every { AmazonQLspService.didChangeConfiguration(any()) } returns Unit
262-
settingsManager.toggleMetricOptIn(true)
263-
settingsManager.toggleMetricOptIn(false)
264-
265-
io.mockk.verify(atLeast = 2) {
266-
AmazonQLspService.didChangeConfiguration(any())
267-
}
268-
}
269254
}
270255

271256
class CodeWhispererSettingUnitTest {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

44
package migration.software.aws.toolkits.jetbrains.services.codewhisperer.customization

0 commit comments

Comments
 (0)