Skip to content

Commit 8fe9d5b

Browse files
authored
feat(amazonq): selective transformation (#5101)
This change is part of selective transformation where we will be giving the option to the user to provide one or multiple diffs for their proposed changes.
1 parent 7fd65de commit 8fe9d5b

27 files changed

+1414
-46
lines changed

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

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,35 @@ import software.aws.toolkits.core.utils.error
2323
import software.aws.toolkits.core.utils.exists
2424
import software.aws.toolkits.core.utils.getLogger
2525
import software.aws.toolkits.core.utils.info
26+
import software.aws.toolkits.jetbrains.core.coroutines.EDT
2627
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
2728
import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
2829
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.NoTokenInitializedException
2930
import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_ERROR_OVERVIEW
3031
import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_EXPIRED
3132
import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
3233
import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener
34+
import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup
35+
import software.aws.toolkits.jetbrains.services.codemodernizer.constants.createViewDiffButton
3336
import software.aws.toolkits.jetbrains.services.codemodernizer.constants.getDownloadedArtifactTextFromType
37+
import software.aws.toolkits.jetbrains.services.codemodernizer.constants.viewSummaryButton
38+
import software.aws.toolkits.jetbrains.services.codemodernizer.controller.CodeTransformChatHelper
39+
import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageContent
40+
import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageType
3441
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact
3542
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformFailureBuildLog
3643
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformHilDownloadArtifact
3744
import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadArtifactResult
3845
import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadFailureReason
3946
import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
4047
import software.aws.toolkits.jetbrains.services.codemodernizer.model.ParseZipFailureReason
48+
import software.aws.toolkits.jetbrains.services.codemodernizer.model.PatchInfo
4149
import software.aws.toolkits.jetbrains.services.codemodernizer.model.UnzipFailureReason
4250
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState
4351
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir
4452
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection
4553
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction
54+
import software.aws.toolkits.jetbrains.utils.notifyInfo
4655
import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
4756
import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
4857
import software.aws.toolkits.resources.message
@@ -57,20 +66,44 @@ import java.util.concurrent.atomic.AtomicBoolean
5766
const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0"
5867
const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request: javax.net.ssl.SSLHandshakeException"
5968
const val INVALID_ARTIFACT_ERROR: String = "Invalid artifact"
60-
61-
class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient) {
69+
val patchDescriptions = mapOf(
70+
"Prepare minimal upgrade to Java 17" to "This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.",
71+
"Popular Enterprise Specifications and Application Frameworks upgrade" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, " +
72+
"and Micronaut 3.",
73+
"HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks" to "This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache " +
74+
"Commons utilities (Collections, IO, Lang, Math), Struts 6.0.",
75+
"Testing Tools and Frameworks upgrade" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, " +
76+
"Jenkins plugins and the Maven Wrapper.",
77+
"Miscellaneous Processing Documentation upgrade" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, " +
78+
"and more.",
79+
"Deprecated API replacement and dependency upgrades" to "This diff patch replaces deprecated APIs and makes additional dependency version upgrades."
80+
)
81+
82+
class ArtifactHandler(
83+
private val project: Project,
84+
private val clientAdaptor: GumbyClient,
85+
private val codeTransformChatHelper: CodeTransformChatHelper? = null,
86+
) {
6287
private val telemetry = CodeTransformTelemetryManager.getInstance(project)
6388
private val downloadedArtifacts = mutableMapOf<JobId, Path>()
6489
private val downloadedSummaries = mutableMapOf<JobId, TransformationSummary>()
6590
private val downloadedBuildLogPath = mutableMapOf<JobId, Path>()
6691
private var isCurrentlyDownloading = AtomicBoolean(false)
92+
private var totalPatchFiles: Int = 0
93+
private var sharedPatchIndex: Int = 0
6794

6895
internal suspend fun displayDiff(job: JobId, source: CodeTransformVCSViewerSrcComponents) {
6996
if (isCurrentlyDownloading.get()) return
7097
when (val result = downloadArtifact(job, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS)) {
7198
is DownloadArtifactResult.Success -> {
7299
if (result.artifact !is CodeModernizerArtifact) return notifyUnableToApplyPatch("")
73-
displayDiffUsingPatch(result.artifact.patch, job, source)
100+
totalPatchFiles = result.artifact.patches.size
101+
if (result.artifact.description == null) {
102+
displayDiffUsingPatch(result.artifact.patches.first(), totalPatchFiles, null, job, source)
103+
} else {
104+
val diffDescription = result.artifact.description[getCurrentPatchIndex()]
105+
displayDiffUsingPatch(result.artifact.patches[getCurrentPatchIndex()], totalPatchFiles, diffDescription, job, source)
106+
}
74107
}
75108
is DownloadArtifactResult.ParseZipFailure -> notifyUnableToApplyPatch(result.failureReason.errorMessage)
76109
is DownloadArtifactResult.UnzipFailure -> notifyUnableToApplyPatch(result.failureReason.errorMessage)
@@ -246,8 +279,14 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
246279
/**
247280
* Opens the built-in patch dialog to display the diff and allowing users to apply the changes locally.
248281
*/
249-
internal fun displayDiffUsingPatch(patchFile: VirtualFile, jobId: JobId, source: CodeTransformVCSViewerSrcComponents) {
250-
runInEdt {
282+
internal suspend fun displayDiffUsingPatch(
283+
patchFile: VirtualFile,
284+
totalPatchFiles: Int,
285+
diffDescription: PatchInfo?,
286+
jobId: JobId,
287+
source: CodeTransformVCSViewerSrcComponents,
288+
) {
289+
withContext(EDT) {
251290
val dialog = ApplyPatchDifferentiatedDialog(
252291
project,
253292
ApplyPatchDefaultExecutor(project),
@@ -256,7 +295,14 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
256295
patchFile,
257296
null,
258297
ChangeListManager.getInstance(project)
259-
.addChangeList(message("codemodernizer.patch.name"), ""),
298+
.addChangeList(
299+
if (diffDescription != null) {
300+
"${diffDescription.name} (${if (diffDescription.isSuccessful) "Success" else "Failure"})"
301+
} else {
302+
patchFile.name
303+
},
304+
""
305+
),
260306
null,
261307
null,
262308
null,
@@ -265,7 +311,44 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
265311
dialog.isModal = true
266312

267313
if (dialog.showAndGet()) {
314+
telemetry.submitSelection("Submit-${diffDescription?.name}")
268315
telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source)
316+
if (diffDescription == null) {
317+
val resultContent = CodeTransformChatMessageContent(
318+
type = CodeTransformChatMessageType.PendingAnswer,
319+
message = message("codemodernizer.chat.message.changes_applied"),
320+
)
321+
codeTransformChatHelper?.updateLastPendingMessage(resultContent)
322+
codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup())
323+
} else {
324+
if (getCurrentPatchIndex() < totalPatchFiles) {
325+
val message = "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. " +
326+
"${patchDescriptions[diffDescription.name]}"
327+
val notificationMessage = "Amazon Q applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles " +
328+
"to your project."
329+
val notificationTitle = "Diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles applied"
330+
setCurrentPatchIndex(getCurrentPatchIndex() + 1)
331+
notifyInfo(notificationTitle, notificationMessage, project)
332+
if (getCurrentPatchIndex() == totalPatchFiles) {
333+
codeTransformChatHelper?.updateLastPendingMessage(
334+
CodeTransformChatMessageContent(type = CodeTransformChatMessageType.PendingAnswer, message = message)
335+
)
336+
} else {
337+
codeTransformChatHelper?.updateLastPendingMessage(
338+
CodeTransformChatMessageContent(
339+
type = CodeTransformChatMessageType.PendingAnswer,
340+
message = message,
341+
buttons = listOf(
342+
createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/$totalPatchFiles"),
343+
viewSummaryButton
344+
)
345+
)
346+
)
347+
}
348+
} else {
349+
codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup())
350+
}
351+
}
269352
} else {
270353
telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Cancel", source)
271354
}
@@ -388,6 +471,12 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
388471

389472
fun getSummary(job: JobId) = downloadedSummaries[job]
390473

474+
private fun getCurrentPatchIndex() = sharedPatchIndex
475+
476+
private fun setCurrentPatchIndex(index: Int) {
477+
sharedPatchIndex = index
478+
}
479+
391480
private fun showSummaryFromFile(summaryFile: File) {
392481
val summaryMarkdownVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(summaryFile)
393482
if (summaryMarkdownVirtualFile != null) {

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -576,12 +576,6 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
576576
resumeJob(session, lastJobId, currentJobResult)
577577
}
578578

579-
private fun displayDiffNotificationAction(jobId: JobId): NotificationAction = NotificationAction.createSimple(
580-
message("codemodernizer.notification.info.modernize_complete.view_diff")
581-
) {
582-
artifactHandler.displayDiffAction(jobId, CodeTransformVCSViewerSrcComponents.ToastNotification)
583-
}
584-
585579
private fun displaySummaryNotificationAction(jobId: JobId) =
586580
NotificationAction.createSimple(message("codemodernizer.notification.info.modernize_complete.view_summary")) {
587581
artifactHandler.showTransformationSummary(jobId)
@@ -638,7 +632,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
638632
message("codemodernizer.notification.info.modernize_partial_complete.title"),
639633
message("codemodernizer.notification.info.modernize_partial_complete.content", result.targetJavaVersion.description),
640634
project,
641-
listOf(displayDiffNotificationAction(result.jobId), displaySummaryNotificationAction(result.jobId), displayFeedbackNotificationAction()),
635+
listOf(displaySummaryNotificationAction(result.jobId), displayFeedbackNotificationAction()),
642636
)
643637
jobId = result.jobId
644638
}
@@ -648,7 +642,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
648642
message("codemodernizer.notification.info.modernize_complete.title"),
649643
message("codemodernizer.notification.info.modernize_complete.content"),
650644
project,
651-
listOf(displayDiffNotificationAction(result.jobId), displaySummaryNotificationAction(result.jobId)),
645+
listOf(displaySummaryNotificationAction(result.jobId)),
652646
)
653647
jobId = result.jobId
654648
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ import java.util.concurrent.atomic.AtomicBoolean
6363
import javax.net.ssl.SSLHandshakeException
6464

6565
const val MAX_ZIP_SIZE = 2000000000 // 2GB
66+
const val EXPLAINABILITY_V1 = "EXPLAINABILITY_V1"
67+
const val SELECTIVE_TRANSFORMATION_V1 = "SELECTIVE_TRANSFORMATION_V1"
6668

6769
// constants for handling SDKClientException
6870
const val CONNECTION_REFUSED_ERROR: String = "Connection refused"

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ private enum class CodeTransformMessageTypes(val type: String) {
3939
CodeTransformStop("codetransform-stop"),
4040
CodeTransformCancel("codetransform-cancel"),
4141
CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"),
42+
CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"),
4243
CodeTransformNew("codetransform-new"),
4344
CodeTransformOpenTransformHub("codetransform-open-transform-hub"),
4445
CodeTransformOpenMvnBuild("codetransform-open-mvn-build"),
@@ -72,6 +73,7 @@ class CodeTransformChatApp : AmazonQApp {
7273
CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class,
7374
CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class,
7475
CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class,
76+
CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class,
7577
CodeTransformMessageTypes.CodeTransformNew.type to IncomingCodeTransformMessage.CodeTransformNew::class,
7678
CodeTransformMessageTypes.CodeTransformOpenTransformHub.type to IncomingCodeTransformMessage.CodeTransformOpenTransformHub::class,
7779
CodeTransformMessageTypes.CodeTransformOpenMvnBuild.type to IncomingCodeTransformMessage.CodeTransformOpenMvnBuild::class,
@@ -166,6 +168,7 @@ class CodeTransformChatApp : AmazonQApp {
166168
is IncomingCodeTransformMessage.CodeTransformStop -> inboundAppMessagesHandler.processCodeTransformStopAction(message.tabId)
167169
is IncomingCodeTransformMessage.ChatPrompt -> inboundAppMessagesHandler.processChatPromptMessage(message)
168170
is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message)
171+
is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message)
169172
is IncomingCodeTransformMessage.CodeTransformNew -> inboundAppMessagesHandler.processCodeTransformNewAction(message)
170173
is IncomingCodeTransformMessage.CodeTransformOpenTransformHub -> inboundAppMessagesHandler.processCodeTransformOpenTransformHub(message)
171174
is IncomingCodeTransformMessage.CodeTransformOpenMvnBuild -> inboundAppMessagesHandler.processCodeTransformOpenMvnBuild(message)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ interface InboundAppMessagesHandler {
2323

2424
suspend fun processCodeTransformConfirmSkipTests(message: IncomingCodeTransformMessage.CodeTransformConfirmSkipTests)
2525

26+
suspend fun processCodeTransformOneOrMultipleDiffs(message: IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs)
27+
2628
suspend fun processCodeTransformOpenTransformHub(message: IncomingCodeTransformMessage.CodeTransformOpenTransformHub)
2729

2830
suspend fun processCodeTransformOpenMvnBuild(message: IncomingCodeTransformMessage.CodeTransformOpenMvnBuild)

plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class GumbyClient(private val project: Project) {
222222
it.timestamp(Instant.now())
223223
it.ideCategory(IdeCategory.JETBRAINS)
224224
it.programmingLanguage { language ->
225-
language.languageName(metrics.programmingLanguage)
225+
language.languageName(metrics.programmingLanguage?.lowercase())
226226
}
227227
it.linesOfCodeChanged(metrics.linesOfCodeChanged)
228228
it.charsOfCodeChanged(metrics.charactersOfCodeChanged)

0 commit comments

Comments
 (0)