Skip to content

Commit 3cf676a

Browse files
author
David Hasani
committed
fix(amazonq): prompt users to re-auth on invalid grant
1 parent 42c1a99 commit 3cf676a

File tree

4 files changed

+50
-36
lines changed

4 files changed

+50
-36
lines changed

plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.intellij.openapi.actionSystem.ActionGroup
88
import com.intellij.openapi.actionSystem.ActionManager
99
import com.intellij.openapi.actionSystem.ActionToolbar
1010
import com.intellij.openapi.application.invokeLater
11+
import com.intellij.openapi.application.runInEdt
1112
import com.intellij.openapi.components.service
1213
import com.intellij.openapi.project.Project
1314
import com.intellij.openapi.projectRoots.JavaSdkVersion
@@ -62,14 +63,16 @@ class CodeModernizerBottomWindowPanelManager(private val project: Project) : JPa
6263
}
6364

6465
private fun setUI(function: () -> Unit) {
65-
lastShownProgressPanel = this.components.firstOrNull { it == fullSizeLoadingPanel || it == buildProgressSplitterPanelManager } ?: lastShownProgressPanel
66-
removeAll()
67-
add(BorderLayout.WEST, toolbar.component)
68-
add(BorderLayout.NORTH, banner)
69-
function.invoke()
70-
updateRunTime()
71-
revalidate()
72-
repaint()
66+
runInEdt {
67+
lastShownProgressPanel = this.components.firstOrNull { it == fullSizeLoadingPanel || it == buildProgressSplitterPanelManager } ?: lastShownProgressPanel
68+
removeAll()
69+
add(BorderLayout.WEST, toolbar.component)
70+
add(BorderLayout.NORTH, banner)
71+
function.invoke()
72+
updateRunTime()
73+
revalidate()
74+
repaint()
75+
}
7376
}
7477

7578
private fun updateRunTime(now: Instant? = null) {

plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package software.aws.toolkits.jetbrains.services.codemodernizer.utils
55

66
import com.fasterxml.jackson.module.kotlin.readValue
7+
import com.intellij.notification.NotificationAction
78
import com.intellij.openapi.project.Project
89
import com.intellij.serviceContainer.AlreadyDisposedException
910
import kotlinx.coroutines.delay
@@ -23,12 +24,14 @@ import software.aws.toolkits.core.utils.WaiterUnrecoverableException
2324
import software.aws.toolkits.core.utils.Waiters.waitUntil
2425
import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager
2526
import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
27+
import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener
2628
import software.aws.toolkits.jetbrains.services.codemodernizer.constants.BILLING_RATE
2729
import software.aws.toolkits.jetbrains.services.codemodernizer.constants.JOB_STATISTICS_TABLE_KEY
2830
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact.Companion.MAPPER
2931
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
3032
import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
3133
import software.aws.toolkits.jetbrains.services.codemodernizer.model.PlanTable
34+
import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
3235
import software.aws.toolkits.resources.message
3336
import java.time.Duration
3437
import java.util.Locale
@@ -64,8 +67,7 @@ suspend fun JobId.pollTransformationStatusAndPlan(
6467
val maxRefreshes = 10
6568
var numRefreshes = 0
6669

67-
// We refresh token at the start of polling, but for some long jobs that runs for 30 minutes plus, tokens may need to be
68-
// refreshed again when AccessDeniedException or InvalidGrantException are caught.
70+
// refresh token at start of polling since local build just prior can take a long time
6971
refreshToken(project)
7072

7173
try {
@@ -113,8 +115,17 @@ suspend fun JobId.pollTransformationStatusAndPlan(
113115
refreshToken(project)
114116
return@waitUntil state
115117
} catch (e: InvalidGrantException) {
116-
if (numRefreshes++ > maxRefreshes) throw e
117-
refreshToken(project)
118+
CodeTransformMessageListener.instance.onCheckAuth()
119+
notifyStickyWarn(
120+
message("codemodernizer.notification.warn.expired_credentials.title"),
121+
message("codemodernizer.notification.warn.expired_credentials.content"),
122+
project,
123+
listOf(
124+
NotificationAction.createSimpleExpiring(message("codemodernizer.notification.warn.action.reauthenticate")) {
125+
CodeTransformMessageListener.instance.onReauthStarted()
126+
}
127+
)
128+
)
118129
return@waitUntil state
119130
} finally {
120131
delay(sleepDurationMillis)

plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import io.mockk.every
66
import io.mockk.just
77
import io.mockk.mockkStatic
88
import io.mockk.runs
9+
import io.mockk.verify
910
import kotlinx.coroutines.runBlocking
1011
import org.assertj.core.api.Assertions.assertThat
1112
import org.junit.Before
@@ -19,16 +20,19 @@ import software.amazon.awssdk.services.codewhispererruntime.model.AccessDeniedEx
1920
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate
2021
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
2122
import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
23+
import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener
2224
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
2325
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText
2426
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getTableMapping
2527
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildFile
2628
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
2729
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken
2830
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
31+
import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
2932
import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
3033
import java.util.concurrent.atomic.AtomicBoolean
3134
import kotlin.io.path.createTempFile
35+
import io.mockk.*
3236

3337
class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase() {
3438
@Before
@@ -114,24 +118,18 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
114118
}
115119

116120
@Test
117-
fun `refresh on invalid grant`() {
118-
val mockInvalidGrantException = Mockito.mock(InvalidGrantException::class.java)
119-
120-
mockkStatic(::refreshToken)
121-
every { refreshToken(any()) } just runs
121+
fun `show re-auth notification on invalid grant exception`() {
122+
mockkStatic(::notifyStickyWarn)
122123

123-
Mockito.doThrow(
124-
mockInvalidGrantException
125-
).doReturn(
126-
exampleGetCodeMigrationResponse,
127-
exampleGetCodeMigrationResponse.replace(TransformationStatus.STARTED),
128-
exampleGetCodeMigrationResponse.replace(TransformationStatus.COMPLETED), // Should stop before this point
129-
).whenever(clientAdaptorSpy).getCodeModernizationJob(any())
124+
val mockMessageListener = mockk<CodeTransformMessageListener>()
125+
mockkObject(CodeTransformMessageListener)
126+
every { CodeTransformMessageListener.instance } returns mockMessageListener
127+
every { mockMessageListener.onCheckAuth() } just runs
130128

131-
Mockito.doReturn(exampleGetCodeMigrationPlanResponse)
132-
.whenever(clientAdaptorSpy).getCodeModernizationPlan(any())
129+
val mockInvalidGrantException = Mockito.mock(InvalidGrantException::class.java)
130+
Mockito.doThrow(mockInvalidGrantException)
131+
.whenever(clientAdaptorSpy).getCodeModernizationJob(any())
133132

134-
val mutableList = mutableListOf<TransformationStatus>()
135133
runBlocking {
136134
jobId.pollTransformationStatusAndPlan(
137135
CodeTransformType.LANGUAGE_UPGRADE,
@@ -142,17 +140,18 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
142140
0,
143141
AtomicBoolean(false),
144142
project
145-
) { _, status, _ ->
146-
mutableList.add(status)
147-
}
143+
) { _, _, _ -> }
148144
}
149-
val expected =
150-
listOf<TransformationStatus>(
151-
exampleGetCodeMigrationResponse.transformationJob().status(),
152-
TransformationStatus.STARTED,
145+
146+
verify {
147+
notifyStickyWarn(
148+
"Your connection to Q has expired",
149+
"Unable to check transformation status as your credentials expired.",
150+
project,
151+
any()
153152
)
154-
assertThat(expected).isEqualTo(mutableList)
155-
io.mockk.verify { refreshToken(any()) }
153+
}
154+
verify { mockMessageListener.onCheckAuth() }
156155
}
157156

158157
@Test

plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ codemodernizer.notification.warn.download_failed_invalid_artifact=Amazon Q was u
778778
codemodernizer.notification.warn.download_failed_other.content=Amazon Q ran into an issue while trying to download your {0}. Please try again. {1}
779779
codemodernizer.notification.warn.download_failed_ssl.content=Please make sure all your certificates for your proxy client have been set up correctly for your IDE.
780780
codemodernizer.notification.warn.download_failed_wildcard.content=Check your IDE proxy settings and remove any wildcard (*) references, and then try viewing the diff again.
781+
codemodernizer.notification.warn.expired_credentials.content=Unable to check transformation status as your credentials expired. Try signing out of Amazon Q and signing back in again if 'Reauthenticate' below does not work.
781782
codemodernizer.notification.warn.expired_credentials.title=Your connection to Q has expired
782783
codemodernizer.notification.warn.invalid_project.description.reason.missing_content_roots=None of your open modules are supported for code transformation with Amazon Q. Amazon Q can upgrade Java 8, Java 11, Java 17, and Java 21 projects built on Maven, with content roots configured.
783784
codemodernizer.notification.warn.invalid_project.description.reason.not_logged_in=Amazon Q cannot start the transformation as you are not logged in with Identity Center or Builder ID. Also ensure that you are not using IntelliJ version 232.8660.185 and that you are not developing on a remote host (uncommon).

0 commit comments

Comments
 (0)