Skip to content

fix(amazonq): Invalidate Obsolete Customization on Profile Switch #5575

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

Merged
merged 34 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8223470
Merge staging into feature/q-region-expansion
aws-toolkit-automation Apr 9, 2025
9105243
call if
evanliu048 Apr 9, 2025
ae016bd
add cache
evanliu048 Apr 9, 2025
c1474fe
linter
evanliu048 Apr 9, 2025
e2967bf
Merge staging into feature/q-region-expansion
aws-toolkit-automation Apr 9, 2025
cbb548d
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 9, 2025
0ec0d1f
Merge staging into feature/q-region-expansion
aws-toolkit-automation Apr 9, 2025
07e63ca
delete ut
evanliu048 Apr 9, 2025
de7a0f0
test
evanliu048 Apr 9, 2025
1a4a5db
Merge branch 'feature/q-region-expansion' into regionExpansion_fixlaunch
evanliu048 Apr 9, 2025
daff262
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 9, 2025
24f57fb
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 10, 2025
7a35aae
revise auth
evanliu048 Apr 10, 2025
b5d3299
re
evanliu048 Apr 10, 2025
29b297a
delete
evanliu048 Apr 10, 2025
3c4d39a
revert
evanliu048 Apr 10, 2025
62ddb32
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 10, 2025
bbc7cce
ut
evanliu048 Apr 10, 2025
ad24bbd
merge
evanliu048 Apr 10, 2025
fbcdf40
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 10, 2025
d3c76bd
reintialize q ui
evanliu048 Apr 10, 2025
5f97d38
Merge branch 'main' into regionExpansion_fixlaunch
rli Apr 10, 2025
a467169
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 10, 2025
790de97
add url
evanliu048 Apr 10, 2025
1673db3
update sdk
evanliu048 Apr 11, 2025
b6f5cd2
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 11, 2025
51c66f0
Merge branch 'main' into regionExpansion_fixlaunch
evanliu048 Apr 14, 2025
0164a61
add a listner in cofig
evanliu048 Apr 14, 2025
46d7188
recover service.json
evanliu048 Apr 14, 2025
a50938c
recover ut
evanliu048 Apr 15, 2025
4e7f678
remove import
evanliu048 Apr 15, 2025
ba3cb42
recover
evanliu048 Apr 15, 2025
5dd8369
add ut
evanliu048 Apr 15, 2025
fb908cc
log
evanliu048 Apr 15, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type" : "bugfix",
"description" : "Amazon Q: Customization now resets with a warning if unavailable in the selected profile."
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import software.aws.toolkits.core.utils.debug
import software.aws.toolkits.core.utils.getLogger
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
import software.aws.toolkits.jetbrains.services.amazonq.calculateIfIamIdentityCenterConnection
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
import software.aws.toolkits.jetbrains.utils.notifyInfo
Expand All @@ -48,6 +50,7 @@ private fun notifyInvalidSelectedCustomization(project: Project) {
}

private fun notifyNewCustomization(project: Project) {
if (ApplicationManager.getApplication().isUnitTestMode) return
notifyInfo(
title = message("codewhisperer.custom.dialog.title"),
content = message("codewhisperer.notification.custom.new_customization"),
Expand Down Expand Up @@ -81,6 +84,18 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe

private var customizationArnOverrideV2: String? = null

init {
ApplicationManager.getApplication().messageBus.connect(this).subscribe(
QRegionProfileSelectedListener.TOPIC,
object : QRegionProfileSelectedListener {
override fun onProfileSelected(project: Project, profile: QRegionProfile?) {
pluginAwareExecuteOnPooledThread {
CodeWhispererModelConfigurator.getInstance().listCustomizations(project, passive = true)
}
}
}
)
}
override fun showConfigDialog(project: Project) {
runInEdt {
calculateIfIamIdentityCenterConnection(project) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.testFramework.ApplicationRule
import com.intellij.testFramework.DisposableRule
import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.registerServiceInstance
import com.intellij.testFramework.replaceService
import com.intellij.util.xmlb.XmlSerializer
import migration.software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator
import org.assertj.core.api.Assertions.assertThat
import org.jdom.output.XMLOutputter
import org.junit.Before
Expand Down Expand Up @@ -40,10 +42,14 @@ import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
import software.aws.toolkits.jetbrains.services.amazonq.FeatureContext
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomizationState
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.DefaultCodeWhispererModelConfigurator
import software.aws.toolkits.jetbrains.utils.xmlElement
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible

Expand Down Expand Up @@ -75,6 +81,7 @@ class CodeWhispererModelConfiguratorTest {
private lateinit var sut: DefaultCodeWhispererModelConfigurator
private lateinit var mockClient: CodeWhispererRuntimeClient
private lateinit var abManager: CodeWhispererFeatureConfigService
private lateinit var mockClintAdaptor: CodeWhispererClientAdaptor

@Before
fun setup() {
Expand All @@ -83,7 +90,11 @@ class CodeWhispererModelConfiguratorTest {
regionProvider.addRegion(Region.US_EAST_1)
regionProvider.addRegion(Region.US_EAST_2)

sut = DefaultCodeWhispererModelConfigurator()
sut = spy(CodeWhispererModelConfigurator.getInstance() as DefaultCodeWhispererModelConfigurator).also { spyInstance ->
ApplicationManager.getApplication().replaceService(
DefaultCodeWhispererModelConfigurator::class.java, spyInstance, disposableRule.disposable
)
}

(ToolkitConnectionManager.getInstance(projectRule.project) as DefaultToolkitConnectionManager).loadState(ToolkitConnectionManagerState())
mockClient.stub {
Expand All @@ -110,6 +121,9 @@ class CodeWhispererModelConfiguratorTest {
abManager,
disposableRule.disposable
)

mockClintAdaptor = mock()
projectRule.project.registerServiceInstance(CodeWhispererClientAdaptor::class.java, mockClintAdaptor)
}

@Test
Expand Down Expand Up @@ -550,4 +564,48 @@ class CodeWhispererModelConfiguratorTest {
assertThat(actual.previousAvailableCustomizations).hasSize(1)
assertThat(actual.previousAvailableCustomizations["fake-sso-url"]).isEqualTo(listOf("arn_1", "arn_2", "arn_3"))
}

@Test
fun `profile switch should keep using existing customization if new list still contains that arn`() {
val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES))
ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn)
val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription")
sut.switchCustomization(projectRule.project, oldCustomization)

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

val fakeCustomizations = listOf(
CodeWhispererCustomization("oldArn", "oldName", "oldDescription")
)
mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations }

ApplicationManager.getApplication().messageBus
.syncPublisher(QRegionProfileSelectedListener.TOPIC)
.onProfileSelected(projectRule.project, null)

assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization)
}

@Test
fun `profile switch should invalidate obsolete customization if it's not in the new list`() {
val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES))
ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn)
val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription")
sut.switchCustomization(projectRule.project, oldCustomization)
assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization)
val fakeCustomizations = listOf(
CodeWhispererCustomization("newArn", "newName", "newDescription")
)
mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations }

val latch = CountDownLatch(1)

ApplicationManager.getApplication().messageBus
.syncPublisher(QRegionProfileSelectedListener.TOPIC)
.onProfileSelected(projectRule.project, null)

latch.await(2, TimeUnit.SECONDS)

assertThat(sut.activeCustomization(projectRule.project)).isNull()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class QRegionProfileManager : PersistentStateComponent<QProfileState>, Disposabl
}
}

project.messageBus
ApplicationManager.getApplication().messageBus
.syncPublisher(QRegionProfileSelectedListener.TOPIC)
.onProfileSelected(project, newProfile)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.intellij.util.messages.Topic

interface QRegionProfileSelectedListener {
companion object {
@Topic.ProjectLevel
@Topic.AppLevel
val TOPIC = Topic.create("QRegionProfileSelected", QRegionProfileSelectedListener::class.java)
}

Expand Down
Loading