Skip to content

Commit bdf9131

Browse files
committed
fix(amazonq): don't reset profile config if validation fails to list profiles
1 parent 9109943 commit bdf9131

File tree

3 files changed

+40
-18
lines changed

3 files changed

+40
-18
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Amazon Q: Fix issue where context menu items are not available after re-opening projects or restarting the IDE"
4+
}

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import org.junit.Rule
1515
import org.junit.Test
1616
import org.mockito.kotlin.any
1717
import org.mockito.kotlin.doReturn
18+
import org.mockito.kotlin.doThrow
1819
import org.mockito.kotlin.mock
1920
import org.mockito.kotlin.spy
2021
import org.mockito.kotlin.stub
@@ -191,20 +192,6 @@ class QRegionProfileManagerTest {
191192

192193
@Test
193194
fun `validateProfile should cross validate selected profile with latest API response for current project and remove it if its not longer accessible`() {
194-
val client = clientRule.create<CodeWhispererRuntimeClient>()
195-
val mockResponse: SdkIterable<Profile> = SdkIterable<Profile> {
196-
listOf(
197-
Profile.builder().profileName("foo").arn("foo-arn-v2").build(),
198-
Profile.builder().profileName("bar").arn("bar-arn").build(),
199-
).toMutableList().iterator()
200-
}
201-
val iterable: ListAvailableProfilesIterable = mock {
202-
on { it.profiles() } doReturn mockResponse
203-
}
204-
client.stub {
205-
onGeneric { listAvailableProfilesPaginator(any<Consumer<ListAvailableProfilesRequest.Builder>>()) } doReturn iterable
206-
}
207-
208195
val activeConn =
209196
ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) ?: fail("connection shouldn't be null")
210197
val anotherConn = authRule.createConnection(ManagedSsoProfile(ssoRegion = "us-east-1", startUrl = "anotherUrl", scopes = Q_SCOPES))
@@ -214,6 +201,11 @@ class QRegionProfileManagerTest {
214201
this.connectionIdToActiveProfile[activeConn.id] = fooProfile
215202
this.connectionIdToActiveProfile[anotherConn.id] = barProfile
216203
}
204+
resourceCache.addEntry(activeConn.getConnectionSettings(), QProfileResources.LIST_REGION_PROFILES, listOf(
205+
QRegionProfile("foo", "foo-arn-v2"),
206+
QRegionProfile("bar", "bar-arn"),
207+
))
208+
217209
sut.loadState(state)
218210
assertThat(sut.activeProfile(project)).isEqualTo(fooProfile)
219211

@@ -222,6 +214,24 @@ class QRegionProfileManagerTest {
222214
assertThat(sut.state.connectionIdToActiveProfile).isEqualTo(mapOf(anotherConn.id to barProfile))
223215
}
224216

217+
@Test
218+
fun `validateProfile does not clear profile if profiles cannot be listed`() {
219+
val activeConn =
220+
ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) ?: fail("connection shouldn't be null")
221+
val anotherConn = authRule.createConnection(ManagedSsoProfile(ssoRegion = "us-east-1", startUrl = "anotherUrl", scopes = Q_SCOPES))
222+
val fooProfile = QRegionProfile("foo", "foo-arn")
223+
val barProfile = QRegionProfile("bar", "bar-arn")
224+
val state = QProfileState().apply {
225+
this.connectionIdToActiveProfile[activeConn.id] = fooProfile
226+
this.connectionIdToActiveProfile[anotherConn.id] = barProfile
227+
}
228+
sut.loadState(state)
229+
assertThat(sut.activeProfile(project)).isEqualTo(fooProfile)
230+
231+
sut.validateProfile(project)
232+
assertThat(sut.activeProfile(project)).isEqualTo(fooProfile)
233+
}
234+
225235
@Test
226236
fun `clientSettings should return the region Q profile specify`() {
227237
MockClientManager.useRealImplementations(disposableRule.disposable)

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import software.amazon.awssdk.core.SdkClient
1919
import software.aws.toolkits.core.TokenConnectionSettings
2020
import software.aws.toolkits.core.utils.debug
2121
import software.aws.toolkits.core.utils.getLogger
22-
import software.aws.toolkits.core.utils.tryOrNull
2322
import software.aws.toolkits.core.utils.warn
2423
import software.aws.toolkits.jetbrains.core.AwsClientManager
2524
import software.aws.toolkits.jetbrains.core.AwsResourceCache
@@ -59,16 +58,24 @@ class QRegionProfileManager : PersistentStateComponent<QProfileState>, Disposabl
5958
)
6059
}
6160

62-
// should be call on project startup to validate if profile is still active
61+
/**
62+
* Called on project startup to validate if selected profile is still active
63+
*/
64+
@Deprecated("This is a giant hack and we are not handling all the cases")
6365
@RequiresBackgroundThread
6466
fun validateProfile(project: Project) {
6567
val conn = getIdcConnectionOrNull(project)
6668
val selected = activeProfile(project) ?: return
67-
val profiles = tryOrNull {
69+
val profiles = try {
6870
listRegionProfiles(project)
71+
} catch (_: Exception) {
72+
// if we can't list profiles assume it is valid
73+
LOG.warn { "Continuing with $selected since listAvailableProfiles failed" }
74+
return
6975
}
7076

71-
if (profiles == null || profiles.none { it.arn == selected.arn }) {
77+
// succeeded in listing profiles, but none match selected
78+
if (profiles?.none { it.arn == selected.arn } == true) {
7279
invalidateProfile(selected.arn)
7380
switchProfile(project, null, intent = QProfileSwitchIntent.Reload)
7481
Telemetry.amazonq.profileState.use { span ->
@@ -83,6 +90,7 @@ class QRegionProfileManager : PersistentStateComponent<QProfileState>, Disposabl
8390

8491
fun listRegionProfiles(project: Project): List<QRegionProfile>? {
8592
val connection = getIdcConnectionOrNull(project) ?: return null
93+
8694
return try {
8795
val connectionSettings = connection.getConnectionSettings()
8896
val mappedProfiles = AwsResourceCache.getInstance().getResourceNow(

0 commit comments

Comments
 (0)