From 629a0537816a0361b1c83cbdc86862c3da2cc69e Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Sat, 2 Nov 2024 18:13:28 -0700 Subject: [PATCH 01/19] initial attempt at showing multiple diff patches, need to sync chat with transformation hub button --- .../codemodernizer/ArtifactHandler.kt | 89 ++++++++++++++----- .../codemodernizer/CodeModernizerSession.kt | 8 +- .../constants/CodeTransformChatItems.kt | 14 ++- .../controller/CodeTransformChatController.kt | 31 +++++-- .../ideMaven/MavenRunnerUtils.kt | 1 + .../model/CodeModernizerArtifact.kt | 46 ++++++++-- .../model/CodeModernizerManifest.kt | 3 + .../CodeModernizerBottomWindowPanelManager.kt | 2 + 8 files changed, 156 insertions(+), 38 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index fbbfadcc991..fcfd83b6ed8 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -3,6 +3,7 @@ package software.aws.toolkits.jetbrains.services.codemodernizer +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.intellij.notification.NotificationAction import com.intellij.openapi.application.runInEdt import com.intellij.openapi.application.runReadAction @@ -15,8 +16,11 @@ import com.intellij.openapi.vcs.changes.patch.ApplyPatchMode import com.intellij.openapi.vcs.changes.patch.ImportToShelfExecutor import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile +import com.jetbrains.rd.generator.nova.PredefinedType +import com.squareup.wire.get import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.amazon.awssdk.services.ssooidc.model.SsoOidcException import software.aws.toolkits.core.utils.error @@ -28,9 +32,18 @@ import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.NoTokenInitializedException import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_ERROR_OVERVIEW import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_EXPIRED +import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformResultChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.getDownloadedArtifactTextFromType +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.createViewDiffButton +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.viewSummaryButton +import software.aws.toolkits.jetbrains.services.codemodernizer.controller.CodeTransformChatHelper +import software.aws.toolkits.jetbrains.services.codemodernizer.messages.Button +import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformButtonId +import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageContent +import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageType import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformFailureBuildLog import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformHilDownloadArtifact @@ -38,7 +51,9 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadArt import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadFailureReason import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.model.ParseZipFailureReason +import software.aws.toolkits.jetbrains.services.codemodernizer.model.PatchInfo import software.aws.toolkits.jetbrains.services.codemodernizer.model.UnzipFailureReason +import software.aws.toolkits.jetbrains.services.codemodernizer.session.ChatSessionStorage import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction @@ -52,24 +67,36 @@ import java.nio.file.Files import java.nio.file.Path import java.time.Instant import java.util.concurrent.atomic.AtomicBoolean +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0" const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request: javax.net.ssl.SSLHandshakeException" const val INVALID_ARTIFACT_ERROR: String = "Invalid artifact" -class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient) { +class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient, private val codeTransformChatHelper: CodeTransformChatHelper? = null) { private val telemetry = CodeTransformTelemetryManager.getInstance(project) private val downloadedArtifacts = mutableMapOf() private val downloadedSummaries = mutableMapOf() private val downloadedBuildLogPath = mutableMapOf() private var isCurrentlyDownloading = AtomicBoolean(false) +// private var currentPatchIndex: Int = 0 + private val scope = CoroutineScope(Dispatchers.Default) + private var totalPatchFiles: Int = 0 + internal suspend fun displayDiff(job: JobId, source: CodeTransformVCSViewerSrcComponents) { if (isCurrentlyDownloading.get()) return when (val result = downloadArtifact(job, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS)) { is DownloadArtifactResult.Success -> { if (result.artifact !is CodeModernizerArtifact) return notifyUnableToApplyPatch("") - displayDiffUsingPatch(result.artifact.patch, job, source) +// notifyStickyInfo("chosen diff", result.artifact.patches[currentPatchIndex].name) +// notifyStickyInfo("chosen description", result.artifact.description[currentPatchIndex].name) + totalPatchFiles = result.artifact.patches.size + val diffDescription = result.artifact.description?.getOrNull(getCurrentPatchIndex()) + displayDiffUsingPatch(result.artifact.patches[getCurrentPatchIndex()], totalPatchFiles, diffDescription, job, source) } is DownloadArtifactResult.ParseZipFailure -> notifyUnableToApplyPatch(result.failureReason.errorMessage) is DownloadArtifactResult.UnzipFailure -> notifyUnableToApplyPatch(result.failureReason.errorMessage) @@ -165,11 +192,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G if (artifactType == TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS) { notifyDownloadStart() } - val downloadResultsResponse = if (artifactType == TransformationDownloadArtifactType.LOGS) { - clientAdaptor.downloadExportResultArchive(job, null, TransformationDownloadArtifactType.LOGS) - } else { - clientAdaptor.downloadExportResultArchive(job) - } +// val downloadResultsResponse = if (artifactType == TransformationDownloadArtifactType.LOGS) { +// clientAdaptor.downloadExportResultArchive(job, null, TransformationDownloadArtifactType.LOGS) +// } else { +// clientAdaptor.downloadExportResultArchive(job) +// } // 3. Convert to zip LOG.info { "Downloaded the export result archive, about to transform to zip" } @@ -177,10 +204,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G val totalDownloadBytes: Int val zipPath: String try { - val result = unzipToPath(downloadResultsResponse) - path = result.first - totalDownloadBytes = result.second - zipPath = path.toAbsolutePath().toString() +// val result = unzipToPath(downloadResultsResponse) +// path = result.first +// totalDownloadBytes = result.second +// zipPath = path.toAbsolutePath().toString() + zipPath = "/Users/ntarakad/Desktop/SampleArtifact.zip" LOG.info { "Successfully converted the download to a zip at $zipPath." } } catch (e: Exception) { LOG.error { e.message.toString() } @@ -195,11 +223,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G } else { DownloadArtifactResult.Success(CodeModernizerArtifact.create(zipPath), zipPath) } - if (artifactType == TransformationDownloadArtifactType.LOGS) { - downloadedBuildLogPath[job] = path - } else { - downloadedArtifacts[job] = path - } +// if (artifactType == TransformationDownloadArtifactType.LOGS) { +// downloadedBuildLogPath[job] = path +// } else { +// downloadedArtifacts[job] = path +// } output } catch (e: RuntimeException) { LOG.error { e.message.toString() } @@ -207,7 +235,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G telemetryErrorMessage = "Unexpected error when downloading result ${e.localizedMessage}" DownloadArtifactResult.ParseZipFailure(ParseZipFailureReason(artifactType, e.message.orEmpty())) } finally { - telemetry.downloadArtifact(mapArtifactTypes(artifactType), downloadStartTime, job, totalDownloadBytes, telemetryErrorMessage) +// telemetry.downloadArtifact(mapArtifactTypes(artifactType), downloadStartTime, job, totalDownloadBytes, telemetryErrorMessage) } } catch (e: Exception) { if (isPreFetch) return DownloadArtifactResult.Skipped @@ -234,7 +262,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G /** * Opens the built-in patch dialog to display the diff and allowing users to apply the changes locally. */ - internal fun displayDiffUsingPatch(patchFile: VirtualFile, jobId: JobId, source: CodeTransformVCSViewerSrcComponents) { + internal suspend fun displayDiffUsingPatch(patchFile: VirtualFile, totalPatchFiles: Int, diffDescription: PatchInfo?, jobId: JobId, source: CodeTransformVCSViewerSrcComponents) { runInEdt { val dialog = ApplyPatchDifferentiatedDialog( project, @@ -244,7 +272,9 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G patchFile, null, ChangeListManager.getInstance(project) - .addChangeList(message("codemodernizer.patch.name"), ""), + .addChangeList( + diffDescription?.name ?: patchFile.name, + ""), null, null, null, @@ -253,7 +283,21 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G dialog.isModal = true if (dialog.showAndGet()) { - telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) + scope.launch { + notifyStickyInfo("diff accepted", if (codeTransformChatHelper == null) "null" else "not null") + telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) + setCurrentPatchIndex(getCurrentPatchIndex() + 1) + if (getCurrentPatchIndex() < totalPatchFiles){ + val resultContent = CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message("codemodernizer.chat.message.result.success"), + buttons = listOf(createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/${totalPatchFiles}"), viewSummaryButton), + ) + codeTransformChatHelper?.updateLastPendingMessage(resultContent) + } else { + codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) + } + } } else { telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Cancel", source) } @@ -434,5 +478,10 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G companion object { val LOG = getLogger() + private var sharedPatchIndex: Int = 0 + fun getCurrentPatchIndex() = sharedPatchIndex + fun setCurrentPatchIndex(index: Int) { + sharedPatchIndex = index + } } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt index 69cff581e04..81fba167892 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt @@ -10,6 +10,8 @@ import com.intellij.util.io.HttpRequests import kotlinx.coroutines.delay import org.apache.commons.codec.digest.DigestUtils import software.amazon.awssdk.core.exception.SdkClientException +import software.amazon.awssdk.services.codewhispererruntime.endpoints.internal.SourceException +import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeResponse import software.amazon.awssdk.services.codewhispererruntime.model.ResumeTransformationResponse import software.amazon.awssdk.services.codewhispererruntime.model.StartTransformationResponse import software.amazon.awssdk.services.codewhispererruntime.model.TransformationJob @@ -210,7 +212,7 @@ class CodeModernizerSession( telemetryErrorMessage = "Cancelled when about to upload project" return CodeModernizerStartJobResult.Cancelled } - uploadId = payload?.let { uploadPayload(it) }.toString() +// uploadId = payload?.let { uploadPayload(it) }.toString() } catch (e: AlreadyDisposedException) { LOG.warn { e.localizedMessage } telemetryErrorMessage = "Disposed when about to upload zip" @@ -284,7 +286,8 @@ class CodeModernizerSession( LOG.warn { "Job was cancelled by user before start job was called" } return CodeModernizerStartJobResult.Cancelled } - val startJobResponse = startJob(uploadId) +// val startJobResponse = startJob(uploadId) + val startJobResponse = StartTransformationResponse.builder().transformationJobId("123").build() state.putJobHistory(sessionContext, TransformationStatus.STARTED, startJobResponse.transformationJobId()) state.currentJobStatus = TransformationStatus.STARTED telemetry.jobStart(startTime, JobId(startJobResponse.transformationJobId())) @@ -423,6 +426,7 @@ class CodeModernizerSession( ): CodeModernizerJobCompletedResult { try { state.currentJobId = jobId + return CodeModernizerJobCompletedResult.JobCompletedSuccessfully(jobId) // add delay to avoid the throttling error delay(1000) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index 24494eb99a1..af2181ddd7a 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -79,7 +79,15 @@ private val viewDiffButton = Button( keepCardAfterClick = true, ) -private val viewSummaryButton = Button( +fun createViewDiffButton(buttonLabel: String): Button { + return Button( + id = CodeTransformButtonId.ViewDiff.id, + text = buttonLabel, + keepCardAfterClick = true + ) +} + +val viewSummaryButton = Button( id = CodeTransformButtonId.ViewSummary.id, text = message("codemodernizer.chat.message.button.view_summary"), keepCardAfterClick = true, @@ -367,7 +375,7 @@ fun buildTransformResumingChatContent() = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.PendingAnswer, ) -fun buildTransformResultChatContent(result: CodeModernizerJobCompletedResult): CodeTransformChatMessageContent { +fun buildTransformResultChatContent(result: CodeModernizerJobCompletedResult, totalPatchFiles: Int): CodeTransformChatMessageContent { val resultMessage = when (result) { is CodeModernizerJobCompletedResult.JobAbortedZipTooLarge -> { "${message( @@ -411,7 +419,7 @@ fun buildTransformResultChatContent(result: CodeModernizerJobCompletedResult): C type = CodeTransformChatMessageType.FinalizedAnswer, message = resultMessage, buttons = if (result is CodeModernizerJobCompletedResult.JobPartiallySucceeded || result is CodeModernizerJobCompletedResult.JobCompletedSuccessfully) { - listOf(viewDiffButton, viewSummaryButton) + listOf(createViewDiffButton(if (totalPatchFiles == 1) "View diff" else "View diff 1/${totalPatchFiles}"), viewSummaryButton) } else if (result is CodeModernizerJobCompletedResult.JobFailedInitialBuild && result.hasBuildLog) { listOf(viewBuildLog) } else { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index 7f9570ee413..69705585151 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -9,7 +9,9 @@ import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.vfs.VirtualFile import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.getLogger @@ -60,13 +62,19 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUs import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSelectionSummaryChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSkipTestsFlagSelectionChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserStopTransformChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.createViewDiffButton +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.viewSummaryButton import software.aws.toolkits.jetbrains.services.codemodernizer.messages.AuthenticationNeededExceptionMessage import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessage +import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageContent +import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageType import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformCommandMessage import software.aws.toolkits.jetbrains.services.codemodernizer.messages.IncomingCodeTransformMessage +import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformHilDownloadArtifact import software.aws.toolkits.jetbrains.services.codemodernizer.model.CustomerSelection +import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadArtifactResult import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadFailureReason import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.model.MAVEN_BUILD_RUN_UNIT_TESTS @@ -92,9 +100,9 @@ class CodeTransformChatController( ) : InboundAppMessagesHandler { private val authController = AuthController() private val messagePublisher = context.messagesFromAppToUi - private val codeModernizerManager = CodeModernizerManager.getInstance(context.project) private val codeTransformChatHelper = CodeTransformChatHelper(context.messagesFromAppToUi, chatSessionStorage) - private val artifactHandler = ArtifactHandler(context.project, GumbyClient.getInstance(context.project)) + private val codeModernizerManager = CodeModernizerManager.getInstance(context.project) + private val artifactHandler = ArtifactHandler(context.project, GumbyClient.getInstance(context.project), codeTransformChatHelper) private val telemetry = CodeTransformTelemetryManager.getInstance(context.project) override suspend fun processTransformQuickAction(message: IncomingCodeTransformMessage.Transform) { @@ -514,10 +522,21 @@ class CodeTransformChatController( if (result is CodeModernizerJobCompletedResult.ZipUploadFailed && result.failureReason is UploadFailureReason.CREDENTIALS_EXPIRED) { return } else { - codeTransformChatHelper.updateLastPendingMessage( - buildTransformResultChatContent(result) - ) - codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) + val downloadResult = artifactHandler.downloadArtifact(CodeModernizerSessionState.getInstance(context.project).currentJobId as JobId, + TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS) + when (downloadResult) { + is DownloadArtifactResult.Success -> { + if (downloadResult.artifact !is CodeModernizerArtifact) return artifactHandler.notifyUnableToApplyPatch("") + codeTransformChatHelper.updateLastPendingMessage( + buildTransformResultChatContent(result, downloadResult.artifact.patches.size) + ) + } + is DownloadArtifactResult.DownloadFailure -> artifactHandler.notifyUnableToDownload(downloadResult.failureReason) + is DownloadArtifactResult.ParseZipFailure -> artifactHandler.notifyUnableToApplyPatch(downloadResult.failureReason.errorMessage) + is DownloadArtifactResult.Skipped -> {} + is DownloadArtifactResult.UnzipFailure -> artifactHandler.notifyUnableToApplyPatch(downloadResult.failureReason.errorMessage) + } + //codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) } } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt index 3c3b5712c11..c56545cebfc 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt @@ -63,6 +63,7 @@ fun runMavenCopyCommands(sourceFolder: File, buildlogBuilder: StringBuilder, log val telemetry = CodeTransformTelemetryManager.getInstance(project) var telemetryErrorMessage = "" var telemetryLocalBuildResult = Result.Succeeded + return MavenCopyCommandsResult.Success(destinationDir.toFile()) logger.info { "Executing IntelliJ bundled Maven" } try { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index cd9f6ae8fe7..9dc962ea227 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -3,6 +3,7 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.model +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.intellij.openapi.util.io.FileUtil.createTempDirectory @@ -14,10 +15,12 @@ import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.warn import software.aws.toolkits.jetbrains.services.codemodernizer.TransformationSummary import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile +import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import java.io.File import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.Path import kotlin.io.path.isDirectory +import kotlin.io.path.name import kotlin.io.path.walk /** @@ -26,16 +29,15 @@ import kotlin.io.path.walk open class CodeModernizerArtifact( val zipPath: String, val manifest: CodeModernizerManifest, - private val patches: List, + val patches: List, + val description: List?, val summary: TransformationSummary, val summaryMarkdownFile: File, ) : CodeTransformDownloadArtifact { - val patch: VirtualFile - get() = patches.first() companion object { private const val maxSupportedVersion = 1.0 - private val tempDir = createTempDirectory("codeTransformArtifacts", null) + private var tempDir = createTempDirectory("codeTransformArtifacts", null) private const val manifestPathInZip = "manifest.json" private const val summaryNameInZip = "summary.md" val LOG = getLogger() @@ -52,16 +54,20 @@ open class CodeModernizerArtifact( LOG.error { "Could not unzip artifact" } throw RuntimeException("Could not unzip artifact") } +// notifyStickyInfo("Zip", path.name) +// notifyStickyInfo("Zip", tempDir.path) + tempDir = tempDir.resolve("SampleArtifact") val manifest = loadManifest() if (manifest.version > maxSupportedVersion) { // If not supported we can still try to use it, i.e. the versions should largely be backwards compatible LOG.warn { "Unsupported version: ${manifest.version}" } } val patches = extractPatches(manifest) + val description = loadDescription(manifest) val summary = extractSummary(manifest) val summaryMarkdownFile = getSummaryFile(manifest) - if (patches.size != 1) throw RuntimeException("Expected 1 patch, but found ${patches.size}") - return CodeModernizerArtifact(zipPath, manifest, patches, summary, summaryMarkdownFile) +// if (patches.size != 1) throw RuntimeException("Expected 1 patch, but found ${patches.size}") + return CodeModernizerArtifact(zipPath, manifest, patches, description, summary, summaryMarkdownFile) } throw RuntimeException("Could not find artifact") } @@ -105,8 +111,34 @@ open class CodeModernizerArtifact( throw RuntimeException("Expected root for patches was not a directory.") } return patchesDir.walk() - .map { fileSystem.refreshAndFindFileByNioFile(it) ?: throw RuntimeException("Could not find patch") } + .filter { it.toString().endsWith(".patch") } + .map { fileSystem.findFileByNioFile(it) ?: throw RuntimeException("Could not find patch") } + .sortedWith(compareBy { it.name }) .toList() } + + @OptIn(ExperimentalPathApi::class) + private fun loadDescription(manifest: CodeModernizerManifest): List? { + val fileSystem = LocalFileSystem.getInstance() + val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot).toFile() + if (!patchesDir.isDirectory) { + throw RuntimeException("Expected root for patches was not a directory.") + } + + val descriptionFile = patchesDir.listFiles() + ?.firstOrNull { it.name.endsWith(".json") } + + if (descriptionFile == null) { + // No JSON description file found, return null + return null + } + + val patchInfoList: List = MAPPER.readValue( + descriptionFile, + MAPPER.typeFactory.constructCollectionType(List::class.java, PatchInfo::class.java) + ) + + return patchInfoList + } } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt index a09ded600c2..3ac185fced5 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt @@ -7,3 +7,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties @JsonIgnoreProperties(ignoreUnknown = true) data class CodeModernizerManifest(val version: Float, val patchesRoot: String, val artifactsRoot: String, val summaryRoot: String) + +@JsonIgnoreProperties(ignoreUnknown = true) +data class PatchInfo (val name: String, val filename: String, val isSuccessful: Boolean) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt index fe26278aedf..1219ca7f407 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt @@ -20,6 +20,8 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.warn +import software.aws.toolkits.jetbrains.services.codemodernizer.ArtifactHandler +import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult import software.aws.toolkits.jetbrains.services.codemodernizer.panels.CodeModernizerBanner import software.aws.toolkits.jetbrains.services.codemodernizer.panels.CodeModernizerJobHistoryTablePanel From 6ef2c1a148649ede0bb69b6bb27823cfda331e55 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Wed, 6 Nov 2024 10:05:42 -0800 Subject: [PATCH 02/19] adding support for different json format --- .../codemodernizer/ArtifactHandler.kt | 14 ++++-- .../model/CodeModernizerArtifact.kt | 48 +++++++++++++------ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index fcfd83b6ed8..2536b6a11ed 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -92,11 +92,15 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G when (val result = downloadArtifact(job, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS)) { is DownloadArtifactResult.Success -> { if (result.artifact !is CodeModernizerArtifact) return notifyUnableToApplyPatch("") -// notifyStickyInfo("chosen diff", result.artifact.patches[currentPatchIndex].name) -// notifyStickyInfo("chosen description", result.artifact.description[currentPatchIndex].name) +// notifyStickyInfo("chosen diff", result.artifact.patches[getCurrentPatchIndex()].name) +// notifyStickyInfo("chosen description", result.artifact.description[getCurrentPatchIndex()].name) totalPatchFiles = result.artifact.patches.size - val diffDescription = result.artifact.description?.getOrNull(getCurrentPatchIndex()) - displayDiffUsingPatch(result.artifact.patches[getCurrentPatchIndex()], totalPatchFiles, diffDescription, job, source) + if (result.artifact.description == null){ + displayDiffUsingPatch(result.artifact.patches.first(), totalPatchFiles, null, job, source) + } else { + val diffDescription = result.artifact.description[getCurrentPatchIndex()] + displayDiffUsingPatch(result.artifact.patches[getCurrentPatchIndex()], totalPatchFiles, diffDescription, job, source) + } } is DownloadArtifactResult.ParseZipFailure -> notifyUnableToApplyPatch(result.failureReason.errorMessage) is DownloadArtifactResult.UnzipFailure -> notifyUnableToApplyPatch(result.failureReason.errorMessage) @@ -284,7 +288,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G if (dialog.showAndGet()) { scope.launch { - notifyStickyInfo("diff accepted", if (codeTransformChatHelper == null) "null" else "not null") +// notifyStickyInfo("diff accepted", if (codeTransformChatHelper == null) "null" else "not null") telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) setCurrentPatchIndex(getCurrentPatchIndex() + 1) if (getCurrentPatchIndex() < totalPatchFiles){ diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index 9dc962ea227..e069fc07d37 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -9,6 +9,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile +import org.gradle.internal.impldep.jcifs.util.DES import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.exists import software.aws.toolkits.core.utils.getLogger @@ -23,6 +24,10 @@ import kotlin.io.path.isDirectory import kotlin.io.path.name import kotlin.io.path.walk +@JsonIgnoreProperties(ignoreUnknown = true) +data class DescriptionContent (val content: List) + + /** * Represents a CodeModernizer artifact. Essentially a wrapper around the manifest file in the downloaded artifact zip. */ @@ -62,8 +67,8 @@ open class CodeModernizerArtifact( // If not supported we can still try to use it, i.e. the versions should largely be backwards compatible LOG.warn { "Unsupported version: ${manifest.version}" } } - val patches = extractPatches(manifest) val description = loadDescription(manifest) + val patches = extractPatches(manifest, description) val summary = extractSummary(manifest) val summaryMarkdownFile = getSummaryFile(manifest) // if (patches.size != 1) throw RuntimeException("Expected 1 patch, but found ${patches.size}") @@ -104,22 +109,40 @@ open class CodeModernizerArtifact( } @OptIn(ExperimentalPathApi::class) - private fun extractPatches(manifest: CodeModernizerManifest): List { + private fun extractPatches(manifest: CodeModernizerManifest, description: List?): List { + if (description == null) { + return listOf(extractSinglePatch(manifest)) + } val fileSystem = LocalFileSystem.getInstance() val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot) if (!patchesDir.isDirectory()) { throw RuntimeException("Expected root for patches was not a directory.") } - return patchesDir.walk() - .filter { it.toString().endsWith(".patch") } - .map { fileSystem.findFileByNioFile(it) ?: throw RuntimeException("Could not find patch") } - .sortedWith(compareBy { it.name }) - .toList() + return description.map { patchInfo -> + val patchFile = patchesDir.resolve(patchInfo.filename) + if (patchFile.toFile().exists()) { + fileSystem.findFileByNioFile(patchFile) + ?: throw RuntimeException("Could not find patch: ${patchInfo.filename}") + } else { + throw RuntimeException("Patch file not found: ${patchInfo.filename}") + } + } + } + @OptIn(ExperimentalPathApi::class) + private fun extractSinglePatch(manifest: CodeModernizerManifest): VirtualFile { + val fileSystem = LocalFileSystem.getInstance() + val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot) + + if (!patchesDir.isDirectory()) { + throw RuntimeException("Expected root for patches was not a directory.") + } + + val diffPatchFile = patchesDir.resolve("diff.patch") + return fileSystem.findFileByNioFile(diffPatchFile)!! } @OptIn(ExperimentalPathApi::class) private fun loadDescription(manifest: CodeModernizerManifest): List? { - val fileSystem = LocalFileSystem.getInstance() val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot).toFile() if (!patchesDir.isDirectory) { throw RuntimeException("Expected root for patches was not a directory.") @@ -132,13 +155,8 @@ open class CodeModernizerArtifact( // No JSON description file found, return null return null } - - val patchInfoList: List = MAPPER.readValue( - descriptionFile, - MAPPER.typeFactory.constructCollectionType(List::class.java, PatchInfo::class.java) - ) - - return patchInfoList + val descriptionContent: DescriptionContent = MAPPER.readValue(descriptionFile, DescriptionContent::class.java) + return descriptionContent.content } } } From 853b40caa296ceebb4316d41f15904765b1598ce Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Thu, 14 Nov 2024 09:16:04 -0800 Subject: [PATCH 03/19] adding new UI messaging for patch descriptions and removing redundant view diff buttons --- .../codemodernizer/ArtifactHandler.kt | 22 ++++++++++++++++--- .../codemodernizer/CodeModernizerManager.kt | 14 ++++++------ .../constants/CodeTransformChatItems.kt | 5 +++++ .../controller/CodeTransformChatController.kt | 3 +++ .../model/CodeModernizerArtifact.kt | 2 +- .../CodeModernizerBottomWindowPanelManager.kt | 2 +- .../resources/MessagesBundle.properties | 8 ++++++- 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index 2536b6a11ed..bae3ea6b042 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -75,6 +75,13 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSt const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0" const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request: javax.net.ssl.SSLHandshakeException" const val INVALID_ARTIFACT_ERROR: String = "Invalid artifact" +val patchDescriptions: Map = mapOf( + "Minimal Compatible Library Upgrade to Java 17" to "This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.", + "Popular Enterprise Specifications and Application Frameworks" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.", + "HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks" to "This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache Commons utilities (Collections, IO, Lang, Math), Struts 6.0.", + "Testing Tools and Frameworks" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, Jenkins plugins and the Maven Wrapper.", + "Miscellaneous Processing Documentation" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more." +) class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient, private val codeTransformChatHelper: CodeTransformChatHelper? = null) { private val telemetry = CodeTransformTelemetryManager.getInstance(project) @@ -212,7 +219,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G // path = result.first // totalDownloadBytes = result.second // zipPath = path.toAbsolutePath().toString() - zipPath = "/Users/ntarakad/Desktop/SampleArtifact.zip" + zipPath = "/Users/ntarakad/Desktop/SampleArtifactOneDiffNoJson.zip" LOG.info { "Successfully converted the download to a zip at $zipPath." } } catch (e: Exception) { LOG.error { e.message.toString() } @@ -277,7 +284,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G null, ChangeListManager.getInstance(project) .addChangeList( - diffDescription?.name ?: patchFile.name, + if (diffDescription != null) { + "${diffDescription.name} (${if (diffDescription.isSuccessful) "Success" else "Failure"})" + } else { + patchFile.name + }, ""), null, null, @@ -292,9 +303,14 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) setCurrentPatchIndex(getCurrentPatchIndex() + 1) if (getCurrentPatchIndex() < totalPatchFiles){ + val message = if (diffDescription != null) { + "I applied the changes in diff patch ${getCurrentPatchIndex()} of $totalPatchFiles. ${patchDescriptions[diffDescription.name]} You can make a commit if the diff shows success. If the diff shows partial success, apply and fix the errors, and start a new transformation." + } else { + "I applied the changes to your project." + } val resultContent = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.PendingAnswer, - message = message("codemodernizer.chat.message.result.success"), + message = message, buttons = listOf(createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/${totalPatchFiles}"), viewSummaryButton), ) codeTransformChatHelper?.updateLastPendingMessage(resultContent) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt index eddaa6a8788..9f3698c5c5e 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt @@ -560,11 +560,11 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo resumeJob(session, lastJobId, currentJobResult) } - private fun displayDiffNotificationAction(jobId: JobId): NotificationAction = NotificationAction.createSimple( - message("codemodernizer.notification.info.modernize_complete.view_diff") - ) { - artifactHandler.displayDiffAction(jobId, CodeTransformVCSViewerSrcComponents.ToastNotification) - } +// private fun displayDiffNotificationAction(jobId: JobId): NotificationAction = NotificationAction.createSimple( +// message("codemodernizer.notification.info.modernize_complete.view_diff") +// ) { +// artifactHandler.displayDiffAction(jobId, CodeTransformVCSViewerSrcComponents.ToastNotification) +// } private fun displaySummaryNotificationAction(jobId: JobId) = NotificationAction.createSimple(message("codemodernizer.notification.info.modernize_complete.view_summary")) { @@ -622,7 +622,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo message("codemodernizer.notification.info.modernize_partial_complete.title"), message("codemodernizer.notification.info.modernize_partial_complete.content", result.targetJavaVersion.description), project, - listOf(displayDiffNotificationAction(result.jobId), displaySummaryNotificationAction(result.jobId), displayFeedbackNotificationAction()), + listOf(displaySummaryNotificationAction(result.jobId), displayFeedbackNotificationAction()), ) jobId = result.jobId } @@ -632,7 +632,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo message("codemodernizer.notification.info.modernize_complete.title"), message("codemodernizer.notification.info.modernize_complete.content"), project, - listOf(displayDiffNotificationAction(result.jobId), displaySummaryNotificationAction(result.jobId)), + listOf(displaySummaryNotificationAction(result.jobId)), ) jobId = result.jobId } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index af2181ddd7a..893b59b1056 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -361,6 +361,11 @@ fun buildTransformBeginChatContent() = CodeTransformChatMessageContent( message = message("codemodernizer.chat.message.transform_begin"), ) +fun buildMultipleDiffsChatContent() = CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message("codemodernizer.chat.message.multiple_patch_descriptions") +) + fun buildTransformInProgressChatContent() = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.PendingAnswer, message = message("codemodernizer.chat.message.transform_in_progress"), diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index 69705585151..b401c983632 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -42,6 +42,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHi import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilRejectContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilResumeWithErrorContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilResumedContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildMultipleDiffsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectInvalidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectValidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup @@ -173,6 +174,7 @@ class CodeTransformChatController( codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } else { codeTransformChatHelper.addNewMessage(buildTransformBeginChatContent()) + codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } return true @@ -503,6 +505,7 @@ class CodeTransformChatController( private suspend fun handleCodeTransformUploadCompleted() { codeTransformChatHelper.addNewMessage(buildTransformBeginChatContent()) + codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index e069fc07d37..6bf8e8da172 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -61,7 +61,7 @@ open class CodeModernizerArtifact( } // notifyStickyInfo("Zip", path.name) // notifyStickyInfo("Zip", tempDir.path) - tempDir = tempDir.resolve("SampleArtifact") + tempDir = tempDir.resolve("SampleArtifactOneDiffNoJson") val manifest = loadManifest() if (manifest.version > maxSupportedVersion) { // If not supported we can still try to use it, i.e. the versions should largely be backwards compatible diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt index 1219ca7f407..646f0e3c11e 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt @@ -209,7 +209,7 @@ class CodeModernizerBottomWindowPanelManager(private val project: Project) : JPa private fun setJobCompletedSuccessfullyUI() { add(BorderLayout.CENTER, buildProgressSplitterPanelManager) buildProgressSplitterPanelManager.apply { - addViewDiffToBanner() +// addViewDiffToBanner() addViewSummaryToBanner() banner.updateContent(message("codemodernizer.toolwindow.banner.run_scan_complete"), AllIcons.Actions.Commit) setSplitPanelStopView() diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index 3d8ea0a76d4..cdd90a64da7 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -618,6 +618,13 @@ codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when build codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests codemodernizer.chat.message.transform_begin=I'm starting to transform your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. +codemodernizer.chat.message.multiple_patch_descriptions=\ +I will be dividing my proposed changes into smaller sections. Here is a description of what each section entails:\n\n\ +? Minimal Compatible Library Upgrade to Java 17: This upgrades dependencies to the minimum compatible versions in Java 17. It also includes updated versions of Springboot as well as JUnit and PowerMockito frameworks.\n\n\ +? Popular Enterprise Specifications Application Frameworks: This group aims to migrate to the latest versions of popular enterprise specifications and application frameworks like Jakarta EE 10 (the new javax namespace), Hibernate 6.2 (a widely used ORM), and Micronaut 3 (a modern, lightweight full-stack framework).\n\n\ +? HTTP Client Utilities Web Frameworks: This section targets upgrades for HTTP client libraries (Apache HTTP Client 5), Apache Commons utilities (Collections, IO, Lang, Math), and web frameworks (Struts 6.0). The goal is to modernize these commonly used libraries and frameworks to their latest versions, ensuring compatibility with Java 17.\n\n\ +? Testing Tools Frameworks: This set upgrades targets testing tools and frameworks like ArchUnit, Mockito, TestContainers, and Cucumber. Additionally, it updates build tools like Jenkins plugins and the Maven Wrapper. The goal is to bring the testing ecosystem and build tooling up-to-date with the latest versions and best practices.\n\n\ +? Miscellaneous Processing Documentation: This group covers a diverse set of upgrades spanning ORMs (JpaRepository), XML processing (JAXB namespace), application servers (WebSphere to Liberty migration), API documentation (Swagger to SpringDoc/OpenAPI), and utilities (Okio, OkHttp, LaunchDarkly) codemodernizer.chat.message.transform_cancelled_by_user=I cancelled your transformation. If you want to start another transformation, choose **Start a new transformation**. codemodernizer.chat.message.transform_in_progress=If I run into any issues, I might pause the transformation to get input from you on how to proceed. codemodernizer.chat.message.transform_stopped_by_user=I stopped your transformation. If you want to start another transformation, choose **Start a new transformation**. @@ -733,7 +740,6 @@ codemodernizer.notification.warn.zip_creation_failed=Amazon Q could not zip the codemodernizer.notification.warn.zip_creation_failed.reasons.unknown=An unexpected error occurred codemodernizer.notification.warn.zip_too_large.content=Sorry, your project size exceeds the Amazon Q Code Transformation upload limit of 2GB. codemodernizer.notification.warn.zip_too_large.title=Project size exceeds limit -codemodernizer.patch.name=Patch with code changes required to upgrade to Java 17 codemodernizer.toolwindow.banner.action.diff=View diff codemodernizer.toolwindow.banner.action.feedback=Provide Feedback codemodernizer.toolwindow.banner.action.plan=View transformation plan From 0429617d0eec2c8d4b96fc4a40b54eec87869dbd Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Fri, 15 Nov 2024 10:53:09 -0800 Subject: [PATCH 04/19] added in forms for one or multiple diffs and made manifest changes accordingly --- .../codemodernizer/ArtifactHandler.kt | 38 ++++++++-------- .../codemodernizer/CodeModernizerSession.kt | 15 ++++--- .../codemodernizer/CodeTransformChatApp.kt | 3 ++ .../InboundAppMessagesHandler.kt | 2 + .../constants/CodeTransformChatItems.kt | 43 +++++++++++++++++++ .../controller/CodeTransformChatController.kt | 26 ++++++++++- .../ideMaven/MavenRunnerUtils.kt | 2 +- .../messages/CodeTransformMessage.kt | 7 +++ .../model/CodeModernizerArtifact.kt | 4 +- .../model/CodeModernizerSessionContext.kt | 6 ++- .../state/CodeModernizerState.kt | 4 ++ .../util/CodeWhispererConstants.kt | 2 +- .../ui/apps/codeTransformChatConnector.ts | 7 +++ .../mynah-ui/src/mynah-ui/ui/commands.ts | 1 + .../src/mynah-ui/ui/forms/constants.ts | 2 + .../resources/MessagesBundle.properties | 18 +++++--- 16 files changed, 141 insertions(+), 39 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index bae3ea6b042..7d66358199c 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -80,7 +80,9 @@ val patchDescriptions: Map = mapOf( "Popular Enterprise Specifications and Application Frameworks" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.", "HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks" to "This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache Commons utilities (Collections, IO, Lang, Math), Struts 6.0.", "Testing Tools and Frameworks" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, Jenkins plugins and the Maven Wrapper.", - "Miscellaneous Processing Documentation" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more." + "Miscellaneous Processing Documentation" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more.", + "Updated dependencies to latest version" to "", + "Upgrade Deprecated API" to "" ) class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient, private val codeTransformChatHelper: CodeTransformChatHelper? = null) { @@ -99,8 +101,6 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G when (val result = downloadArtifact(job, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS)) { is DownloadArtifactResult.Success -> { if (result.artifact !is CodeModernizerArtifact) return notifyUnableToApplyPatch("") -// notifyStickyInfo("chosen diff", result.artifact.patches[getCurrentPatchIndex()].name) -// notifyStickyInfo("chosen description", result.artifact.description[getCurrentPatchIndex()].name) totalPatchFiles = result.artifact.patches.size if (result.artifact.description == null){ displayDiffUsingPatch(result.artifact.patches.first(), totalPatchFiles, null, job, source) @@ -203,11 +203,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G if (artifactType == TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS) { notifyDownloadStart() } -// val downloadResultsResponse = if (artifactType == TransformationDownloadArtifactType.LOGS) { -// clientAdaptor.downloadExportResultArchive(job, null, TransformationDownloadArtifactType.LOGS) -// } else { -// clientAdaptor.downloadExportResultArchive(job) -// } + val downloadResultsResponse = if (artifactType == TransformationDownloadArtifactType.LOGS) { + clientAdaptor.downloadExportResultArchive(job, null, TransformationDownloadArtifactType.LOGS) + } else { + clientAdaptor.downloadExportResultArchive(job) + } // 3. Convert to zip LOG.info { "Downloaded the export result archive, about to transform to zip" } @@ -215,11 +215,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G val totalDownloadBytes: Int val zipPath: String try { -// val result = unzipToPath(downloadResultsResponse) -// path = result.first -// totalDownloadBytes = result.second -// zipPath = path.toAbsolutePath().toString() - zipPath = "/Users/ntarakad/Desktop/SampleArtifactOneDiffNoJson.zip" + val result = unzipToPath(downloadResultsResponse) + path = result.first + totalDownloadBytes = result.second + zipPath = path.toAbsolutePath().toString() +// zipPath = "/Users/ntarakad/Desktop/SampleArtifactOneDiffNoJson.zip" LOG.info { "Successfully converted the download to a zip at $zipPath." } } catch (e: Exception) { LOG.error { e.message.toString() } @@ -234,11 +234,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G } else { DownloadArtifactResult.Success(CodeModernizerArtifact.create(zipPath), zipPath) } -// if (artifactType == TransformationDownloadArtifactType.LOGS) { -// downloadedBuildLogPath[job] = path -// } else { -// downloadedArtifacts[job] = path -// } + if (artifactType == TransformationDownloadArtifactType.LOGS) { + downloadedBuildLogPath[job] = path + } else { + downloadedArtifacts[job] = path + } output } catch (e: RuntimeException) { LOG.error { e.message.toString() } @@ -246,7 +246,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G telemetryErrorMessage = "Unexpected error when downloading result ${e.localizedMessage}" DownloadArtifactResult.ParseZipFailure(ParseZipFailureReason(artifactType, e.message.orEmpty())) } finally { -// telemetry.downloadArtifact(mapArtifactTypes(artifactType), downloadStartTime, job, totalDownloadBytes, telemetryErrorMessage) + telemetry.downloadArtifact(mapArtifactTypes(artifactType), downloadStartTime, job, totalDownloadBytes, telemetryErrorMessage) } } catch (e: Exception) { if (isPreFetch) return DownloadArtifactResult.Skipped diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt index 81fba167892..7e9d023ba19 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt @@ -69,6 +69,7 @@ const val UPLOAD_ZIP_MANIFEST_VERSION = 1.0F const val MAX_ZIP_SIZE = 2000000000 // 2GB const val HIL_1P_UPGRADE_CAPABILITY = "HIL_1pDependency_VersionUpgrade" const val EXPLAINABILITY_V1 = "EXPLAINABILITY_V1" +const val SELECTIVE_TRANSFORMATION_V1 = "SELECTIVE_TRANSFORMATION_V1" // constants for handling SDKClientException const val CONNECTION_REFUSED_ERROR: String = "Connection refused" @@ -212,7 +213,7 @@ class CodeModernizerSession( telemetryErrorMessage = "Cancelled when about to upload project" return CodeModernizerStartJobResult.Cancelled } -// uploadId = payload?.let { uploadPayload(it) }.toString() + uploadId = payload?.let { uploadPayload(it) }.toString() } catch (e: AlreadyDisposedException) { LOG.warn { e.localizedMessage } telemetryErrorMessage = "Disposed when about to upload zip" @@ -273,9 +274,9 @@ class CodeModernizerSession( return CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER(e.localizedMessage)) } finally { telemetry.uploadProject(payloadSize, startTime, true, telemetryErrorMessage) - if (payload != null) { - deleteUploadArtifact(payload) - } +// if (payload != null) { +// deleteUploadArtifact(payload) +// } } // Send upload completion message to chat (only if successful) @@ -286,8 +287,8 @@ class CodeModernizerSession( LOG.warn { "Job was cancelled by user before start job was called" } return CodeModernizerStartJobResult.Cancelled } -// val startJobResponse = startJob(uploadId) - val startJobResponse = StartTransformationResponse.builder().transformationJobId("123").build() + val startJobResponse = startJob(uploadId) +// val startJobResponse = StartTransformationResponse.builder().transformationJobId("123").build() state.putJobHistory(sessionContext, TransformationStatus.STARTED, startJobResponse.transformationJobId()) state.currentJobStatus = TransformationStatus.STARTED telemetry.jobStart(startTime, JobId(startJobResponse.transformationJobId())) @@ -426,7 +427,7 @@ class CodeModernizerSession( ): CodeModernizerJobCompletedResult { try { state.currentJobId = jobId - return CodeModernizerJobCompletedResult.JobCompletedSuccessfully(jobId) +// return CodeModernizerJobCompletedResult.JobCompletedSuccessfully(jobId) // add delay to avoid the throttling error delay(1000) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt index 4077362f11c..94f0874463e 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt @@ -36,6 +36,7 @@ private enum class CodeTransformMessageTypes(val type: String) { CodeTransformStop("codetransform-stop"), CodeTransformCancel("codetransform-cancel"), CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"), + CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"), CodeTransformNew("codetransform-new"), CodeTransformOpenTransformHub("codetransform-open-transform-hub"), CodeTransformOpenMvnBuild("codetransform-open-mvn-build"), @@ -66,6 +67,7 @@ class CodeTransformChatApp : AmazonQApp { CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class, CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class, CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class, + CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class, CodeTransformMessageTypes.CodeTransformNew.type to IncomingCodeTransformMessage.CodeTransformNew::class, CodeTransformMessageTypes.CodeTransformOpenTransformHub.type to IncomingCodeTransformMessage.CodeTransformOpenTransformHub::class, CodeTransformMessageTypes.CodeTransformOpenMvnBuild.type to IncomingCodeTransformMessage.CodeTransformOpenMvnBuild::class, @@ -156,6 +158,7 @@ class CodeTransformChatApp : AmazonQApp { is IncomingCodeTransformMessage.CodeTransformCancel -> inboundAppMessagesHandler.processCodeTransformCancelAction(message) is IncomingCodeTransformMessage.CodeTransformStop -> inboundAppMessagesHandler.processCodeTransformStopAction(message.tabId) is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message) + is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message) is IncomingCodeTransformMessage.CodeTransformNew -> inboundAppMessagesHandler.processCodeTransformNewAction(message) is IncomingCodeTransformMessage.CodeTransformOpenTransformHub -> inboundAppMessagesHandler.processCodeTransformOpenTransformHub(message) is IncomingCodeTransformMessage.CodeTransformOpenMvnBuild -> inboundAppMessagesHandler.processCodeTransformOpenMvnBuild(message) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt index 284a1008017..9295506f95f 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt @@ -17,6 +17,8 @@ interface InboundAppMessagesHandler { suspend fun processCodeTransformConfirmSkipTests(message: IncomingCodeTransformMessage.CodeTransformConfirmSkipTests) + suspend fun processCodeTransformOneOrMultipleDiffs(message: IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs) + suspend fun processCodeTransformOpenTransformHub(message: IncomingCodeTransformMessage.CodeTransformOpenTransformHub) suspend fun processCodeTransformOpenMvnBuild(message: IncomingCodeTransformMessage.CodeTransformOpenMvnBuild) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index 893b59b1056..2328ac05bc4 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -55,6 +55,13 @@ private val confirmSkipTestsSelectionButton = Button( id = CodeTransformButtonId.ConfirmSkipTests.id, ) +private val confirmOneOrMultipleDiffsSelectionButton = Button( + keepCardAfterClick = false, + waitMandatoryFormItems = true, + text = message("codemodernizer.chat.message.button.confirm"), + id = CodeTransformButtonId.ConfirmOneOrMultipleDiffs.id, +) + private val openMvnBuildButton = Button( id = CodeTransformButtonId.OpenMvnBuild.id, text = message("codemodernizer.chat.message.button.view_build"), @@ -165,6 +172,22 @@ private val selectSkipTestsFlagFormItem = FormItem( ) ) +private val selectOneOrMultipleDiffsFlagFormItem = FormItem( + id = CodeTransformFormItemId.SelectOneOrMultipleDiffsFlag.id, + title = message("codemodernizer.chat.form.user_selection.item.choose_one_or_multiple_diffs_option"), + mandatory = true, + options = listOf( + FormItemOption( + label = message("codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff"), + value = message("codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff"), + ), + FormItemOption( + label = message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs"), + value = message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs"), + ) + ) +) + private fun getUserSelectionFormattedMarkdown(moduleName: String): String = """ ### ${message("codemodernizer.chat.prompt.title.details")} ------------- @@ -231,12 +254,32 @@ fun buildUserInputSkipTestsFlagChatContent(): CodeTransformChatMessageContent = formItems = listOf(selectSkipTestsFlagFormItem), type = CodeTransformChatMessageType.FinalizedAnswer, ) +fun buildUserInputOneOrMultipleDiffsChatIntroContent(): CodeTransformChatMessageContent = + CodeTransformChatMessageContent( + message = message("codemodernizer.chat.message.one_or_multiple_diffs"), + type = CodeTransformChatMessageType.FinalizedAnswer, + ) +fun buildUserInputOneOrMultipleDiffsFlagChatContent(): CodeTransformChatMessageContent = + CodeTransformChatMessageContent( + message = message("codemodernizer.chat.form.user_selection.title"), + buttons = listOf( + confirmOneOrMultipleDiffsSelectionButton, + cancelUserSelectionButton, + ), + formItems = listOf(selectOneOrMultipleDiffsFlagFormItem), + type = CodeTransformChatMessageType.FinalizedAnswer, + ) fun buildUserSkipTestsFlagSelectionChatContent(skipTestsSelection: String) = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.FinalizedAnswer, message = message("codemodernizer.chat.message.skip_tests_form.response", skipTestsSelection.lowercase()) ) +fun buildUserOneOrMultipleDiffsSelectionChatContent(oneOrMultipleDiffsSelection: String) = CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.FinalizedAnswer, + message = message("codemodernizer.chat.message.one_or_multiple_diffs_form.response", oneOrMultipleDiffsSelection.lowercase()) +) + fun buildUserInputChatContent(project: Project, validationResult: ValidationResult): CodeTransformChatMessageContent { val moduleBuildFiles = validationResult.validatedBuildFiles diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index b401c983632..5873fba21f7 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -22,8 +22,10 @@ import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthFollowUpType import software.aws.toolkits.jetbrains.services.codemodernizer.ArtifactHandler import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager +import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.HilTelemetryMetaData import software.aws.toolkits.jetbrains.services.codemodernizer.InboundAppMessagesHandler +import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFORMATION_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformActionMessage import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformCommand @@ -58,8 +60,11 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserCancelledChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserHilSelection import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputSkipTestsFlagChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputSkipTestsFlagChatIntroContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserOneOrMultipleDiffsSelectionChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSelectionSummaryChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSkipTestsFlagSelectionChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserStopTransformChatContent @@ -251,9 +256,28 @@ class CodeTransformChatController( else -> MAVEN_BUILD_RUN_UNIT_TESTS } codeTransformChatHelper.addNewMessage(buildUserSkipTestsFlagSelectionChatContent(message.skipTestsSelection)) - codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) +// codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) codeModernizerManager.codeTransformationSession?.let { it.sessionContext.customBuildCommand = customBuildCommand +// codeModernizerManager.runLocalMavenBuild(context.project, it) + } + codeTransformChatHelper.run { + addNewMessage(buildUserInputOneOrMultipleDiffsChatIntroContent()) + addNewMessage(buildUserInputOneOrMultipleDiffsFlagChatContent()) + } + } + + override suspend fun processCodeTransformOneOrMultipleDiffs(message: IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs) { + val transformCapabilities = when (message.oneOrMultipleDiffsSelection) { + message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs") -> listOf( + EXPLAINABILITY_V1, SELECTIVE_TRANSFORMATION_V1) + else -> listOf( + EXPLAINABILITY_V1) + } + codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection)) + codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) + codeModernizerManager.codeTransformationSession?.let { + it.sessionContext.transformCapabilities = transformCapabilities codeModernizerManager.runLocalMavenBuild(context.project, it) } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt index c56545cebfc..e35755fef68 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt @@ -63,7 +63,7 @@ fun runMavenCopyCommands(sourceFolder: File, buildlogBuilder: StringBuilder, log val telemetry = CodeTransformTelemetryManager.getInstance(project) var telemetryErrorMessage = "" var telemetryLocalBuildResult = Result.Succeeded - return MavenCopyCommandsResult.Success(destinationDir.toFile()) +// return MavenCopyCommandsResult.Success(destinationDir.toFile()) logger.info { "Executing IntelliJ bundled Maven" } try { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt index 0fab137e222..815576e9a1d 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt @@ -19,6 +19,7 @@ enum class CodeTransformButtonId(val id: String) { StartTransformation("codetransform-input-confirm"), CancelTransformation("codetransform-input-cancel"), ConfirmSkipTests("codetransform-input-confirm-skip-tests"), + ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"), StopTransformation("stop_transform"), OpenTransformationHub("open_transformation_hub"), OpenMvnBuild("open_mvn_build"), @@ -34,6 +35,7 @@ enum class CodeTransformFormItemId(val id: String) { SelectModule("module"), SelectTargetVersion("targetVersion"), SelectSkipTestsFlag("skipTestsSelection"), + SelectOneOrMultipleDiffsFlag("oneOrMultipleDiffsSelection"), DependencyVersion("dependencyVersion"), } @@ -88,6 +90,11 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage { val skipTestsSelection: String, ) : IncomingCodeTransformMessage + data class CodeTransformConfirmOneOrMultipleDiffs( + @JsonProperty("tabID") val tabId: String, + val oneOrMultipleDiffsSelection: String, + ) : IncomingCodeTransformMessage + data class CodeTransformOpenMvnBuild( @JsonProperty("tabID") val tabId: String, ) : IncomingCodeTransformMessage diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index 6bf8e8da172..df289b993fd 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -42,7 +42,7 @@ open class CodeModernizerArtifact( companion object { private const val maxSupportedVersion = 1.0 - private var tempDir = createTempDirectory("codeTransformArtifacts", null) + private val tempDir = createTempDirectory("codeTransformArtifacts", null) private const val manifestPathInZip = "manifest.json" private const val summaryNameInZip = "summary.md" val LOG = getLogger() @@ -61,7 +61,7 @@ open class CodeModernizerArtifact( } // notifyStickyInfo("Zip", path.name) // notifyStickyInfo("Zip", tempDir.path) - tempDir = tempDir.resolve("SampleArtifactOneDiffNoJson") +// tempDir = tempDir.resolve("SampleArtifactOneDiffNoJson") val manifest = loadManifest() if (manifest.version > maxSupportedVersion) { // If not supported we can still try to use it, i.e. the versions should largely be backwards compatible diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt index 22e0774c728..ada8fe30780 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt @@ -16,6 +16,7 @@ import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.info import software.aws.toolkits.core.utils.putNextEntry +import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_DEPENDENCIES_ROOT_NAME import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_MANIFEST_FILE_NAME import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runDependencyReportCommands @@ -26,6 +27,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.toolwindow.CodeMo import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactPomFolder import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilDependenciesRootDir import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilUploadZip +import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.resources.message import java.io.File import java.io.IOException @@ -55,6 +57,7 @@ data class CodeModernizerSessionContext( val configurationFile: VirtualFile, val sourceJavaVersion: JavaSdkVersion, val targetJavaVersion: JavaSdkVersion, + var transformCapabilities: List = listOf(EXPLAINABILITY_V1), var customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS, // run unit tests by default ) { private val mapper = jacksonObjectMapper() @@ -203,7 +206,7 @@ data class CodeModernizerSessionContext( val outputFile = createTemporaryZipFile { zip -> // 1) Manifest file val dependenciesRoot = if (depDirectory != null) "$ZIP_DEPENDENCIES_PATH/${depDirectory.name}" else null - mapper.writeValueAsString(ZipManifest(dependenciesRoot = dependenciesRoot, customBuildCommand = customBuildCommand)) + mapper.writeValueAsString(ZipManifest(dependenciesRoot = dependenciesRoot, transformCapabilities = transformCapabilities, customBuildCommand = customBuildCommand)) .byteInputStream() .use { zip.putNextEntry(Path(MANIFEST_PATH).toString(), it) @@ -253,6 +256,7 @@ data class CodeModernizerSessionContext( zip.putNextEntry(Path(BUILD_LOG_PATH).toString(), it) } }.toFile() + notifyStickyInfo("output zip", outputFile.path) if (depDirectory != null) ZipCreationResult.Succeeded(outputFile) else ZipCreationResult.Missing1P(outputFile) } catch (e: NoSuchFileException) { throw CodeModernizerException("Source folder not found") diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt index 3eedffc1234..82c75fcb155 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.components.BaseState import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.util.xmlb.annotations.Property +import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerSessionContext import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.model.MAVEN_BUILD_RUN_UNIT_TESTS @@ -17,6 +18,7 @@ enum class JobDetails { CONFIGURATION_FILE_PATH, TARGET_JAVA_VERSION, SOURCE_JAVA_VERSION, + TRANSFORM_CAPABILITIES, CUSTOM_BUILD_COMMAND, } @@ -31,6 +33,7 @@ fun buildState(context: CodeModernizerSessionContext, isJobOngoing: Boolean, job JobDetails.CONFIGURATION_FILE_PATH to context.configurationFile.path, JobDetails.TARGET_JAVA_VERSION to context.targetJavaVersion.description, JobDetails.SOURCE_JAVA_VERSION to context.sourceJavaVersion.description, + JobDetails.TRANSFORM_CAPABILITIES to context.transformCapabilities.toString(), JobDetails.CUSTOM_BUILD_COMMAND to context.customBuildCommand ) ) @@ -64,6 +67,7 @@ class CodeModernizerState : BaseState() { configurationFile, sourceJavaSdkVersion, targetJavaSdkVersion, + listOf(EXPLAINABILITY_V1), //should this be from lastJobContext? , defaulting to one diff lastJobContext[JobDetails.CUSTOM_BUILD_COMMAND] ?: MAVEN_BUILD_RUN_UNIT_TESTS // default to running unit tests ) } diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt index 1e11c245b10..4a8d4c7b06b 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt @@ -119,7 +119,7 @@ object CodeWhispererConstants { } object Config { - const val CODEWHISPERER_ENDPOINT = "https://codewhisperer.us-east-1.amazonaws.com/" // PROD + const val CODEWHISPERER_ENDPOINT = "https://rts.alpha-us-west-2.codewhisperer.ai.aws.dev/" // PROD const val CODEWHISPERER_IDPOOL_ID = "us-east-1:70717e99-906f-4add-908c-bd9074a2f5b9" val Sigv4ClientRegion = Region.US_EAST_1 val BearerClientRegion = Region.US_EAST_1 diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts index 70382918819..62e89dc3607 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts @@ -232,6 +232,13 @@ export class CodeTransformChatConnector { tabType: 'codetransform', skipTestsSelection: action.formItemValues?.skipTestsSelection }) + } else if (action.id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs) { + this.sendMessageToExtension({ + command: 'codetransform-confirm-one-or-multiple-diffs', + tabID, + tabType: 'codetransform', + oneOrMultipleDiffsSelection: action.formItemValues?.oneOrMultipleDiffsSelection + }) } else if (action.id === FormButtonIds.OpenTransformationHub) { this.sendMessageToExtension({ command: 'codetransform-open-transform-hub', diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts index c1405a1a6eb..3e737811a7e 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts @@ -33,6 +33,7 @@ type MessageCommand = | 'codetransform-cancel' | 'codetransform-stop' | 'codetransform-confirm-skip-tests' + | 'codetransform-confirm-one-or-multiple-diffs' | 'codetransform-new' | 'codetransform-open-transform-hub' | 'codetransform-open-mvn-build' diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts index c81ed0a36e5..1f3edbdf6e0 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts @@ -7,6 +7,7 @@ export const enum FormButtonIds { CodeTransformInputConfirm = 'codetransform-input-confirm', CodeTransformInputCancel = 'codetransform-input-cancel', CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests', + CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs', OpenMvnBuild = 'open_mvn_build', StopTransform = 'stop_transform', OpenTransformationHub = 'open_transformation_hub', @@ -23,6 +24,7 @@ export const isFormButtonCodeTransform = (id: string): boolean => { id === FormButtonIds.CodeTransformInputConfirm || id === FormButtonIds.CodeTransformInputCancel || id === FormButtonIds.CodeTransformInputSkipTests || + id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs || id === FormButtonIds.CodeTransformViewDiff || id === FormButtonIds.CodeTransformViewSummary || id === FormButtonIds.CodeTransformViewBuildLog || diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index cdd90a64da7..2e30e332a55 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -562,6 +562,7 @@ code.aws.workspaces.short=Dev Environments codemodernizer.builderrordialog.description.title=Error occurred when building your project codemodernizer.chat.form.user_selection.item.choose_module=Choose a module to transform codemodernizer.chat.form.user_selection.item.choose_skip_tests_option=Choose to skip unit tests +codemodernizer.chat.form.user_selection.item.choose_one_or_multiple_diffs_option=Choose how to receive proposed changes codemodernizer.chat.form.user_selection.item.choose_target_version=Choose the target code version codemodernizer.chat.form.user_selection.title=Q - Code transformation codemodernizer.chat.message.absolute_path_detected=I detected {0} potential absolute file path(s) in your {1} file: **{2}**. Absolute file paths might cause issues when I build your code. Any errors will show up in the build log. @@ -615,16 +616,19 @@ codemodernizer.chat.message.result.zip_too_large=Sorry, your project size exceed codemodernizer.chat.message.resume_ongoing=I'm still transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. codemodernizer.chat.message.skip_tests=I will build your module using `mvn test` by default. If you would like me to build your module without running unit tests, I will use `mvn test-compile`. codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module. +codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} when providing the proposed changes. codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests +codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff +codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs codemodernizer.chat.message.transform_begin=I'm starting to transform your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. -codemodernizer.chat.message.multiple_patch_descriptions=\ -I will be dividing my proposed changes into smaller sections. Here is a description of what each section entails:\n\n\ -? Minimal Compatible Library Upgrade to Java 17: This upgrades dependencies to the minimum compatible versions in Java 17. It also includes updated versions of Springboot as well as JUnit and PowerMockito frameworks.\n\n\ -? Popular Enterprise Specifications Application Frameworks: This group aims to migrate to the latest versions of popular enterprise specifications and application frameworks like Jakarta EE 10 (the new javax namespace), Hibernate 6.2 (a widely used ORM), and Micronaut 3 (a modern, lightweight full-stack framework).\n\n\ -? HTTP Client Utilities Web Frameworks: This section targets upgrades for HTTP client libraries (Apache HTTP Client 5), Apache Commons utilities (Collections, IO, Lang, Math), and web frameworks (Struts 6.0). The goal is to modernize these commonly used libraries and frameworks to their latest versions, ensuring compatibility with Java 17.\n\n\ -? Testing Tools Frameworks: This set upgrades targets testing tools and frameworks like ArchUnit, Mockito, TestContainers, and Cucumber. Additionally, it updates build tools like Jenkins plugins and the Maven Wrapper. The goal is to bring the testing ecosystem and build tooling up-to-date with the latest versions and best practices.\n\n\ -? Miscellaneous Processing Documentation: This group covers a diverse set of upgrades spanning ORMs (JpaRepository), XML processing (JAXB namespace), application servers (WebSphere to Liberty migration), API documentation (Swagger to SpringDoc/OpenAPI), and utilities (Okio, OkHttp, LaunchDarkly) +codemodernizer.chat.message.one_or_multiple_diffs=\ +I can now divide the transformation results into diff patches if you would like to review and accept each diff with fewer changes:\n\n\ +- Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito.\n\n\ +- Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ +- HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ +- Testing Tools Frameworks: Testing tools like ArchUnit, Mockito, and TestContainers and build tools like Jenkins and Maven Wrapper.\n\n\ +- Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI. codemodernizer.chat.message.transform_cancelled_by_user=I cancelled your transformation. If you want to start another transformation, choose **Start a new transformation**. codemodernizer.chat.message.transform_in_progress=If I run into any issues, I might pause the transformation to get input from you on how to proceed. codemodernizer.chat.message.transform_stopped_by_user=I stopped your transformation. If you want to start another transformation, choose **Start a new transformation**. From 5f7c508fbbe4c5b5f3da10873e312dd13bd7630b Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Fri, 15 Nov 2024 11:13:38 -0800 Subject: [PATCH 05/19] removing old multiple patches description --- .../codemodernizer/controller/CodeTransformChatController.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index 5873fba21f7..6ad49fb2477 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -179,7 +179,7 @@ class CodeTransformChatController( codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } else { codeTransformChatHelper.addNewMessage(buildTransformBeginChatContent()) - codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) +// codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } return true @@ -529,7 +529,7 @@ class CodeTransformChatController( private suspend fun handleCodeTransformUploadCompleted() { codeTransformChatHelper.addNewMessage(buildTransformBeginChatContent()) - codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) +// codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } From 80e5b8f82589025037f51135cb0dad0d1a562b87 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Fri, 15 Nov 2024 16:50:46 -0800 Subject: [PATCH 06/19] fixing patch descriptions message --- .../software/aws/toolkits/resources/MessagesBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index 2e30e332a55..1e10298a32f 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -623,7 +623,7 @@ codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs codemodernizer.chat.message.transform_begin=I'm starting to transform your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. codemodernizer.chat.message.one_or_multiple_diffs=\ -I can now divide the transformation results into diff patches if you would like to review and accept each diff with fewer changes:\n\n\ +I can now divide the transformation results into diff patches (if applicable to the app) if you would like to review and accept each diff with fewer changes:\n\n\ - Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito.\n\n\ - Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ - HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ From 9b6c1d44deea2f5482aadaf90686a9ad93490f72 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Sat, 16 Nov 2024 20:25:10 -0800 Subject: [PATCH 07/19] fixed issue with undefined in changes applied message and addressing unused imports and minor comments --- .../codemodernizer/ArtifactHandler.kt | 23 ++++--------------- .../codemodernizer/CodeModernizerSession.kt | 10 +++----- .../constants/CodeTransformChatItems.kt | 5 ---- .../controller/CodeTransformChatController.kt | 10 -------- .../model/CodeModernizerArtifact.kt | 14 +++-------- .../model/CodeModernizerManifest.kt | 3 +++ .../model/CodeModernizerSessionContext.kt | 1 - .../CodeModernizerBottomWindowPanelManager.kt | 2 -- 8 files changed, 14 insertions(+), 54 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index 7d66358199c..1ac6ff75703 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -3,7 +3,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer -import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.intellij.notification.NotificationAction import com.intellij.openapi.application.runInEdt import com.intellij.openapi.application.runReadAction @@ -16,11 +15,8 @@ import com.intellij.openapi.vcs.changes.patch.ApplyPatchMode import com.intellij.openapi.vcs.changes.patch.ImportToShelfExecutor import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile -import com.jetbrains.rd.generator.nova.PredefinedType -import com.squareup.wire.get import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.serialization.Serializable import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.amazon.awssdk.services.ssooidc.model.SsoOidcException import software.aws.toolkits.core.utils.error @@ -32,16 +28,12 @@ import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.NoTokenInitializedException import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_ERROR_OVERVIEW import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_EXPIRED -import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformResultChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.getDownloadedArtifactTextFromType import software.aws.toolkits.jetbrains.services.codemodernizer.constants.createViewDiffButton import software.aws.toolkits.jetbrains.services.codemodernizer.constants.viewSummaryButton import software.aws.toolkits.jetbrains.services.codemodernizer.controller.CodeTransformChatHelper -import software.aws.toolkits.jetbrains.services.codemodernizer.messages.Button -import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformButtonId import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageContent import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageType import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact @@ -53,7 +45,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.model.ParseZipFailureReason import software.aws.toolkits.jetbrains.services.codemodernizer.model.PatchInfo import software.aws.toolkits.jetbrains.services.codemodernizer.model.UnzipFailureReason -import software.aws.toolkits.jetbrains.services.codemodernizer.session.ChatSessionStorage import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction @@ -69,18 +60,17 @@ import java.time.Instant import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0" const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request: javax.net.ssl.SSLHandshakeException" const val INVALID_ARTIFACT_ERROR: String = "Invalid artifact" val patchDescriptions: Map = mapOf( - "Minimal Compatible Library Upgrade to Java 17" to "This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.", - "Popular Enterprise Specifications and Application Frameworks" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.", + "Prepare minimal upgrade to Java 17" to "This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.", + "Popular Enterprise Specifications and Application Frameworks upgrade" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.", "HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks" to "This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache Commons utilities (Collections, IO, Lang, Math), Struts 6.0.", - "Testing Tools and Frameworks" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, Jenkins plugins and the Maven Wrapper.", - "Miscellaneous Processing Documentation" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more.", + "Testing Tools and Frameworks upgrade" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, Jenkins plugins and the Maven Wrapper.", + "Miscellaneous Processing Documentation upgrade" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more.", "Updated dependencies to latest version" to "", "Upgrade Deprecated API" to "" ) @@ -91,7 +81,6 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G private val downloadedSummaries = mutableMapOf() private val downloadedBuildLogPath = mutableMapOf() private var isCurrentlyDownloading = AtomicBoolean(false) -// private var currentPatchIndex: Int = 0 private val scope = CoroutineScope(Dispatchers.Default) private var totalPatchFiles: Int = 0 @@ -219,7 +208,6 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G path = result.first totalDownloadBytes = result.second zipPath = path.toAbsolutePath().toString() -// zipPath = "/Users/ntarakad/Desktop/SampleArtifactOneDiffNoJson.zip" LOG.info { "Successfully converted the download to a zip at $zipPath." } } catch (e: Exception) { LOG.error { e.message.toString() } @@ -299,9 +287,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G if (dialog.showAndGet()) { scope.launch { -// notifyStickyInfo("diff accepted", if (codeTransformChatHelper == null) "null" else "not null") telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) - setCurrentPatchIndex(getCurrentPatchIndex() + 1) if (getCurrentPatchIndex() < totalPatchFiles){ val message = if (diffDescription != null) { "I applied the changes in diff patch ${getCurrentPatchIndex()} of $totalPatchFiles. ${patchDescriptions[diffDescription.name]} You can make a commit if the diff shows success. If the diff shows partial success, apply and fix the errors, and start a new transformation." @@ -317,6 +303,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G } else { codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) } + setCurrentPatchIndex(getCurrentPatchIndex() + 1) } } else { telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Cancel", source) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt index 7e9d023ba19..2ce8c78d360 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt @@ -10,8 +10,6 @@ import com.intellij.util.io.HttpRequests import kotlinx.coroutines.delay import org.apache.commons.codec.digest.DigestUtils import software.amazon.awssdk.core.exception.SdkClientException -import software.amazon.awssdk.services.codewhispererruntime.endpoints.internal.SourceException -import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeResponse import software.amazon.awssdk.services.codewhispererruntime.model.ResumeTransformationResponse import software.amazon.awssdk.services.codewhispererruntime.model.StartTransformationResponse import software.amazon.awssdk.services.codewhispererruntime.model.TransformationJob @@ -274,9 +272,9 @@ class CodeModernizerSession( return CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER(e.localizedMessage)) } finally { telemetry.uploadProject(payloadSize, startTime, true, telemetryErrorMessage) -// if (payload != null) { -// deleteUploadArtifact(payload) -// } + if (payload != null) { + deleteUploadArtifact(payload) + } } // Send upload completion message to chat (only if successful) @@ -288,7 +286,6 @@ class CodeModernizerSession( return CodeModernizerStartJobResult.Cancelled } val startJobResponse = startJob(uploadId) -// val startJobResponse = StartTransformationResponse.builder().transformationJobId("123").build() state.putJobHistory(sessionContext, TransformationStatus.STARTED, startJobResponse.transformationJobId()) state.currentJobStatus = TransformationStatus.STARTED telemetry.jobStart(startTime, JobId(startJobResponse.transformationJobId())) @@ -427,7 +424,6 @@ class CodeModernizerSession( ): CodeModernizerJobCompletedResult { try { state.currentJobId = jobId -// return CodeModernizerJobCompletedResult.JobCompletedSuccessfully(jobId) // add delay to avoid the throttling error delay(1000) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index 2328ac05bc4..f5b09146aa8 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -404,11 +404,6 @@ fun buildTransformBeginChatContent() = CodeTransformChatMessageContent( message = message("codemodernizer.chat.message.transform_begin"), ) -fun buildMultipleDiffsChatContent() = CodeTransformChatMessageContent( - type = CodeTransformChatMessageType.PendingAnswer, - message = message("codemodernizer.chat.message.multiple_patch_descriptions") -) - fun buildTransformInProgressChatContent() = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.PendingAnswer, message = message("codemodernizer.chat.message.transform_in_progress"), diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index 6ad49fb2477..a6a85245c18 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -9,7 +9,6 @@ import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.vfs.VirtualFile import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.aws.toolkits.core.utils.debug @@ -44,7 +43,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHi import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilRejectContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilResumeWithErrorContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilResumedContent -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildMultipleDiffsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectInvalidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectValidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup @@ -68,12 +66,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUs import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSelectionSummaryChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSkipTestsFlagSelectionChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserStopTransformChatContent -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.createViewDiffButton -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.viewSummaryButton import software.aws.toolkits.jetbrains.services.codemodernizer.messages.AuthenticationNeededExceptionMessage import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessage -import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageContent -import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageType import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformCommandMessage import software.aws.toolkits.jetbrains.services.codemodernizer.messages.IncomingCodeTransformMessage import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact @@ -179,7 +173,6 @@ class CodeTransformChatController( codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } else { codeTransformChatHelper.addNewMessage(buildTransformBeginChatContent()) -// codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } return true @@ -256,10 +249,8 @@ class CodeTransformChatController( else -> MAVEN_BUILD_RUN_UNIT_TESTS } codeTransformChatHelper.addNewMessage(buildUserSkipTestsFlagSelectionChatContent(message.skipTestsSelection)) -// codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) codeModernizerManager.codeTransformationSession?.let { it.sessionContext.customBuildCommand = customBuildCommand -// codeModernizerManager.runLocalMavenBuild(context.project, it) } codeTransformChatHelper.run { addNewMessage(buildUserInputOneOrMultipleDiffsChatIntroContent()) @@ -529,7 +520,6 @@ class CodeTransformChatController( private suspend fun handleCodeTransformUploadCompleted() { codeTransformChatHelper.addNewMessage(buildTransformBeginChatContent()) -// codeTransformChatHelper.addNewMessage(buildMultipleDiffsChatContent()) codeTransformChatHelper.addNewMessage(buildTransformInProgressChatContent()) } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index df289b993fd..da968c54b97 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -3,29 +3,22 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.model -import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile -import org.gradle.internal.impldep.jcifs.util.DES import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.exists import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.warn import software.aws.toolkits.jetbrains.services.codemodernizer.TransformationSummary import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile -import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import java.io.File import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.Path import kotlin.io.path.isDirectory -import kotlin.io.path.name -import kotlin.io.path.walk -@JsonIgnoreProperties(ignoreUnknown = true) -data class DescriptionContent (val content: List) /** @@ -59,9 +52,6 @@ open class CodeModernizerArtifact( LOG.error { "Could not unzip artifact" } throw RuntimeException("Could not unzip artifact") } -// notifyStickyInfo("Zip", path.name) -// notifyStickyInfo("Zip", tempDir.path) -// tempDir = tempDir.resolve("SampleArtifactOneDiffNoJson") val manifest = loadManifest() if (manifest.version > maxSupportedVersion) { // If not supported we can still try to use it, i.e. the versions should largely be backwards compatible @@ -138,7 +128,9 @@ open class CodeModernizerArtifact( } val diffPatchFile = patchesDir.resolve("diff.patch") - return fileSystem.findFileByNioFile(diffPatchFile)!! + return fileSystem.findFileByNioFile(diffPatchFile.parent.resolve("diff.patch")) + ?: throw IllegalStateException("Could not find diff.patch in directory: ${diffPatchFile.parent}") + } @OptIn(ExperimentalPathApi::class) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt index 3ac185fced5..a00d7238cc3 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt @@ -10,3 +10,6 @@ data class CodeModernizerManifest(val version: Float, val patchesRoot: String, v @JsonIgnoreProperties(ignoreUnknown = true) data class PatchInfo (val name: String, val filename: String, val isSuccessful: Boolean) + +@JsonIgnoreProperties(ignoreUnknown = true) +data class DescriptionContent (val content: List) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt index ada8fe30780..7753bbf872a 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt @@ -256,7 +256,6 @@ data class CodeModernizerSessionContext( zip.putNextEntry(Path(BUILD_LOG_PATH).toString(), it) } }.toFile() - notifyStickyInfo("output zip", outputFile.path) if (depDirectory != null) ZipCreationResult.Succeeded(outputFile) else ZipCreationResult.Missing1P(outputFile) } catch (e: NoSuchFileException) { throw CodeModernizerException("Source folder not found") diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt index 646f0e3c11e..39c795d8048 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt @@ -20,8 +20,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.warn -import software.aws.toolkits.jetbrains.services.codemodernizer.ArtifactHandler -import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult import software.aws.toolkits.jetbrains.services.codemodernizer.panels.CodeModernizerBanner import software.aws.toolkits.jetbrains.services.codemodernizer.panels.CodeModernizerJobHistoryTablePanel From 61b088b875801cb9d73ed08b85c2b8321f366b80 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Sun, 17 Nov 2024 17:21:33 -0800 Subject: [PATCH 08/19] updated messaging for one or multiple diffs when job success/partial success --- .../constants/CodeTransformChatItems.kt | 12 ++++++++++-- .../aws/toolkits/resources/MessagesBundle.properties | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index f5b09146aa8..b2ffeb07874 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -432,10 +432,18 @@ fun buildTransformResultChatContent(result: CodeModernizerJobCompletedResult, to buildZipUploadFailedChatMessage(result.failureReason) } is CodeModernizerJobCompletedResult.JobCompletedSuccessfully -> { - message("codemodernizer.chat.message.result.success") + if (totalPatchFiles == 1){ + message("codemodernizer.chat.message.result.success") + } else { + message("codemodernizer.chat.message.result.success.multiple_diffs") + } } is CodeModernizerJobCompletedResult.JobPartiallySucceeded -> { - message("codemodernizer.chat.message.result.partially_success") + if (totalPatchFiles == 1){ + message("codemodernizer.chat.message.result.partially_success") + } else { + message("codemodernizer.chat.message.result.partially_success.multiple_diffs") + } } is CodeModernizerJobCompletedResult.JobFailed -> { message("codemodernizer.chat.message.result.fail_with_known_reason", result.failureReason) diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index 1e10298a32f..d2731c48f8c 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -611,7 +611,9 @@ codemodernizer.chat.message.result.fail_initial_build=I am having trouble buildi codemodernizer.chat.message.result.fail_initial_build_no_build_log=I am having trouble building your project in the secure build environment: {0}. codemodernizer.chat.message.result.fail_with_known_reason=Sorry, I couldn''t complete the transformation. {0} codemodernizer.chat.message.result.partially_success=I upgraded part of your code to Java 17. You can review the diff to see my proposed changes and accept or reject them. The transformation summary has details about the files I updated and the errors that prevented a complete transformation. +codemodernizer.chat.message.result.partially_success.multiple_diffs= I upgraded part of your code to Java 17. You can review the diff to see my proposed changes and accept or reject them. If you reject the diff, you will not be able to see the diffs later. The transformation summary has details about the files I updated and the errors that prevented a complete transformation. codemodernizer.chat.message.result.success=I successfully upgraded your code to Java 17. You can review the diff to see my proposed changes and accept or reject them. The transformation summary has details about the files I updated. +codemodernizer.chat.message.result.success.multiple_diffs=I successfully upgraded your code to Java 17. You can review the diff to see my proposed changes and accept or reject them. If you reject the diff, you will not be able to see the diffs later. The transformation summary has details about the files I updated. codemodernizer.chat.message.result.zip_too_large=Sorry, your project size exceeds the Amazon Q Code Transformation upload limit of 2GB. codemodernizer.chat.message.resume_ongoing=I'm still transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. codemodernizer.chat.message.skip_tests=I will build your module using `mvn test` by default. If you would like me to build your module without running unit tests, I will use `mvn test-compile`. From f89c49f8a8c6a0e15e2ec14d415f58a469833b4f Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Sun, 17 Nov 2024 21:09:52 -0800 Subject: [PATCH 09/19] fixing one diff and off by one error for multiple diffs and addressing build log errors --- .../codemodernizer/ArtifactHandler.kt | 26 +++++++++++-------- .../codemodernizer/CodeModernizerManager.kt | 6 ----- .../constants/CodeTransformChatItems.kt | 6 +---- .../ideMaven/MavenRunnerUtils.kt | 1 - .../model/CodeModernizerArtifact.kt | 15 +++++------ .../CodeModernizerBottomWindowPanelManager.kt | 3 --- .../state/CodeModernizerState.kt | 2 +- .../util/CodeWhispererConstants.kt | 2 +- .../resources/MessagesBundle.properties | 22 ++++++++-------- 9 files changed, 35 insertions(+), 48 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index 1ac6ff75703..ae3180be59a 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -58,8 +58,6 @@ import java.nio.file.Files import java.nio.file.Path import java.time.Instant import java.util.concurrent.atomic.AtomicBoolean -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0" @@ -67,21 +65,26 @@ const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request const val INVALID_ARTIFACT_ERROR: String = "Invalid artifact" val patchDescriptions: Map = mapOf( "Prepare minimal upgrade to Java 17" to "This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.", - "Popular Enterprise Specifications and Application Frameworks upgrade" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.", - "HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks" to "This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache Commons utilities (Collections, IO, Lang, Math), Struts 6.0.", - "Testing Tools and Frameworks upgrade" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, Jenkins plugins and the Maven Wrapper.", - "Miscellaneous Processing Documentation upgrade" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more.", + "Popular Enterprise Specifications and Application Frameworks upgrade" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, " + + "and Micronaut 3.", + "HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks" to "This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache " + + "Commons utilities (Collections, IO, Lang, Math), Struts 6.0.", + "Testing Tools and Frameworks upgrade" to "This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, Cucumber, and additionally, " + + "Jenkins plugins and the Maven Wrapper.", + "Miscellaneous Processing Documentation upgrade" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, " + + "and more.", "Updated dependencies to latest version" to "", "Upgrade Deprecated API" to "" ) -class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient, private val codeTransformChatHelper: CodeTransformChatHelper? = null) { +class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient, + private val codeTransformChatHelper: CodeTransformChatHelper? = null) { private val telemetry = CodeTransformTelemetryManager.getInstance(project) private val downloadedArtifacts = mutableMapOf() private val downloadedSummaries = mutableMapOf() private val downloadedBuildLogPath = mutableMapOf() private var isCurrentlyDownloading = AtomicBoolean(false) - private val scope = CoroutineScope(Dispatchers.Default) +// private val scope = CoroutineScope(Dispatchers.Default) private var totalPatchFiles: Int = 0 @@ -261,7 +264,8 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G /** * Opens the built-in patch dialog to display the diff and allowing users to apply the changes locally. */ - internal suspend fun displayDiffUsingPatch(patchFile: VirtualFile, totalPatchFiles: Int, diffDescription: PatchInfo?, jobId: JobId, source: CodeTransformVCSViewerSrcComponents) { + internal suspend fun displayDiffUsingPatch(patchFile: VirtualFile, totalPatchFiles: Int, diffDescription: PatchInfo?, jobId: JobId, + source: CodeTransformVCSViewerSrcComponents) { runInEdt { val dialog = ApplyPatchDifferentiatedDialog( project, @@ -286,11 +290,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G dialog.isModal = true if (dialog.showAndGet()) { - scope.launch { + projectCoroutineScope(project).launch { telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) if (getCurrentPatchIndex() < totalPatchFiles){ val message = if (diffDescription != null) { - "I applied the changes in diff patch ${getCurrentPatchIndex()} of $totalPatchFiles. ${patchDescriptions[diffDescription.name]} You can make a commit if the diff shows success. If the diff shows partial success, apply and fix the errors, and start a new transformation." + "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. ${patchDescriptions[diffDescription.name]}" } else { "I applied the changes to your project." } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt index 9f3698c5c5e..3fd66447418 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt @@ -560,12 +560,6 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo resumeJob(session, lastJobId, currentJobResult) } -// private fun displayDiffNotificationAction(jobId: JobId): NotificationAction = NotificationAction.createSimple( -// message("codemodernizer.notification.info.modernize_complete.view_diff") -// ) { -// artifactHandler.displayDiffAction(jobId, CodeTransformVCSViewerSrcComponents.ToastNotification) -// } - private fun displaySummaryNotificationAction(jobId: JobId) = NotificationAction.createSimple(message("codemodernizer.notification.info.modernize_complete.view_summary")) { artifactHandler.showTransformationSummary(jobId) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index b2ffeb07874..c96603b4917 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -87,11 +87,7 @@ private val viewDiffButton = Button( ) fun createViewDiffButton(buttonLabel: String): Button { - return Button( - id = CodeTransformButtonId.ViewDiff.id, - text = buttonLabel, - keepCardAfterClick = true - ) + return Button(id = CodeTransformButtonId.ViewDiff.id, text = buttonLabel, keepCardAfterClick = true) } val viewSummaryButton = Button( diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt index e35755fef68..3c3b5712c11 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt @@ -63,7 +63,6 @@ fun runMavenCopyCommands(sourceFolder: File, buildlogBuilder: StringBuilder, log val telemetry = CodeTransformTelemetryManager.getInstance(project) var telemetryErrorMessage = "" var telemetryLocalBuildResult = Result.Succeeded -// return MavenCopyCommandsResult.Success(destinationDir.toFile()) logger.info { "Executing IntelliJ bundled Maven" } try { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index da968c54b97..d8b4aa5f41a 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -18,7 +18,7 @@ import java.io.File import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.Path import kotlin.io.path.isDirectory - +import kotlin.io.path.walk /** @@ -61,7 +61,6 @@ open class CodeModernizerArtifact( val patches = extractPatches(manifest, description) val summary = extractSummary(manifest) val summaryMarkdownFile = getSummaryFile(manifest) -// if (patches.size != 1) throw RuntimeException("Expected 1 patch, but found ${patches.size}") return CodeModernizerArtifact(zipPath, manifest, patches, description, summary, summaryMarkdownFile) } throw RuntimeException("Could not find artifact") @@ -101,7 +100,7 @@ open class CodeModernizerArtifact( @OptIn(ExperimentalPathApi::class) private fun extractPatches(manifest: CodeModernizerManifest, description: List?): List { if (description == null) { - return listOf(extractSinglePatch(manifest)) + return extractSinglePatch(manifest) } val fileSystem = LocalFileSystem.getInstance() val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot) @@ -119,17 +118,15 @@ open class CodeModernizerArtifact( } } @OptIn(ExperimentalPathApi::class) - private fun extractSinglePatch(manifest: CodeModernizerManifest): VirtualFile { + private fun extractSinglePatch(manifest: CodeModernizerManifest): List { val fileSystem = LocalFileSystem.getInstance() val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot) - if (!patchesDir.isDirectory()) { throw RuntimeException("Expected root for patches was not a directory.") } - - val diffPatchFile = patchesDir.resolve("diff.patch") - return fileSystem.findFileByNioFile(diffPatchFile.parent.resolve("diff.patch")) - ?: throw IllegalStateException("Could not find diff.patch in directory: ${diffPatchFile.parent}") + return patchesDir.walk() + .map { fileSystem.refreshAndFindFileByNioFile(it) ?: throw RuntimeException("Could not find diff.patch") } + .toList() } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt index 39c795d8048..8920687d979 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/managers/CodeModernizerBottomWindowPanelManager.kt @@ -207,7 +207,6 @@ class CodeModernizerBottomWindowPanelManager(private val project: Project) : JPa private fun setJobCompletedSuccessfullyUI() { add(BorderLayout.CENTER, buildProgressSplitterPanelManager) buildProgressSplitterPanelManager.apply { -// addViewDiffToBanner() addViewSummaryToBanner() banner.updateContent(message("codemodernizer.toolwindow.banner.run_scan_complete"), AllIcons.Actions.Commit) setSplitPanelStopView() @@ -278,8 +277,6 @@ class CodeModernizerBottomWindowPanelManager(private val project: Project) : JPa fun addPlanToBanner() = banner.updateActions(banner.showPlanAction) - fun addViewDiffToBanner() = banner.updateActions(banner.showDiffAction) - fun addViewSummaryToBanner() = banner.updateActions(banner.showSummaryAction) private fun stopTimer() { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt index 82c75fcb155..b951a87791f 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt @@ -67,7 +67,7 @@ class CodeModernizerState : BaseState() { configurationFile, sourceJavaSdkVersion, targetJavaSdkVersion, - listOf(EXPLAINABILITY_V1), //should this be from lastJobContext? , defaulting to one diff + listOf(EXPLAINABILITY_V1), //default to one diff lastJobContext[JobDetails.CUSTOM_BUILD_COMMAND] ?: MAVEN_BUILD_RUN_UNIT_TESTS // default to running unit tests ) } diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt index 4a8d4c7b06b..1e11c245b10 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt @@ -119,7 +119,7 @@ object CodeWhispererConstants { } object Config { - const val CODEWHISPERER_ENDPOINT = "https://rts.alpha-us-west-2.codewhisperer.ai.aws.dev/" // PROD + const val CODEWHISPERER_ENDPOINT = "https://codewhisperer.us-east-1.amazonaws.com/" // PROD const val CODEWHISPERER_IDPOOL_ID = "us-east-1:70717e99-906f-4add-908c-bd9074a2f5b9" val Sigv4ClientRegion = Region.US_EAST_1 val BearerClientRegion = Region.US_EAST_1 diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index d2731c48f8c..4677d16e268 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -561,8 +561,8 @@ code.aws.workspaces=Amazon CodeCatalyst code.aws.workspaces.short=Dev Environments codemodernizer.builderrordialog.description.title=Error occurred when building your project codemodernizer.chat.form.user_selection.item.choose_module=Choose a module to transform -codemodernizer.chat.form.user_selection.item.choose_skip_tests_option=Choose to skip unit tests codemodernizer.chat.form.user_selection.item.choose_one_or_multiple_diffs_option=Choose how to receive proposed changes +codemodernizer.chat.form.user_selection.item.choose_skip_tests_option=Choose to skip unit tests codemodernizer.chat.form.user_selection.item.choose_target_version=Choose the target code version codemodernizer.chat.form.user_selection.title=Q - Code transformation codemodernizer.chat.message.absolute_path_detected=I detected {0} potential absolute file path(s) in your {1} file: **{2}**. Absolute file paths might cause issues when I build your code. Any errors will show up in the build log. @@ -606,6 +606,16 @@ codemodernizer.chat.message.hil.user_rejected=I'll continue upgrading your modul codemodernizer.chat.message.local_build_begin=I'm building your module. This can take up to 10 minutes, depending on the size of your module. codemodernizer.chat.message.local_build_failed=Sorry, I couldn't run the Maven clean install command to build your module. codemodernizer.chat.message.local_build_success=I was able to build your module and will start uploading your code. +codemodernizer.chat.message.one_or_multiple_diffs=\ +I can now divide the transformation results into diff patches (if applicable to the app) if you would like to review and accept each diff with fewer changes:\n\n\ +- Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito.\n\n\ +- Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ +- HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ +- Testing Tools Frameworks: Testing tools like ArchUnit, Mockito, and TestContainers and build tools like Jenkins and Maven Wrapper.\n\n\ +- Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI. +codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs +codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff +codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} when providing the proposed changes. codemodernizer.chat.message.result.fail=Sorry, I ran into an issue during the transformation. Please try again. codemodernizer.chat.message.result.fail_initial_build=I am having trouble building your project in the secure build environment and couldn't complete the transformation. codemodernizer.chat.message.result.fail_initial_build_no_build_log=I am having trouble building your project in the secure build environment: {0}. @@ -618,19 +628,9 @@ codemodernizer.chat.message.result.zip_too_large=Sorry, your project size exceed codemodernizer.chat.message.resume_ongoing=I'm still transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. codemodernizer.chat.message.skip_tests=I will build your module using `mvn test` by default. If you would like me to build your module without running unit tests, I will use `mvn test-compile`. codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module. -codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} when providing the proposed changes. codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests -codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff -codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs codemodernizer.chat.message.transform_begin=I'm starting to transform your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub. -codemodernizer.chat.message.one_or_multiple_diffs=\ -I can now divide the transformation results into diff patches (if applicable to the app) if you would like to review and accept each diff with fewer changes:\n\n\ -- Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito.\n\n\ -- Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ -- HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ -- Testing Tools Frameworks: Testing tools like ArchUnit, Mockito, and TestContainers and build tools like Jenkins and Maven Wrapper.\n\n\ -- Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI. codemodernizer.chat.message.transform_cancelled_by_user=I cancelled your transformation. If you want to start another transformation, choose **Start a new transformation**. codemodernizer.chat.message.transform_in_progress=If I run into any issues, I might pause the transformation to get input from you on how to proceed. codemodernizer.chat.message.transform_stopped_by_user=I stopped your transformation. If you want to start another transformation, choose **Start a new transformation**. From 7c961bac7aa044afe25457276335f874048b8e7c Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Mon, 18 Nov 2024 12:30:13 -0800 Subject: [PATCH 10/19] added unit tests and fixing off by one logic and detekt errors --- .../codemodernizer/ArtifactHandler.kt | 33 +- .../constants/CodeTransformChatItems.kt | 4 +- .../controller/CodeTransformChatController.kt | 14 +- .../model/CodeModernizerArtifact.kt | 5 +- .../model/CodeModernizerManifest.kt | 4 +- .../model/CodeModernizerSessionContext.kt | 5 +- .../state/CodeModernizerState.kt | 2 +- .../codemodernizer/diffPatchOutput.json | 1 + .../codemodernizer/min_jdk_upgrade.patch | 161 ++++ ...lar_enterprise_application_framework.patch | 15 + .../tst-resources/codemodernizer/simple.zip | Bin 1623 -> 42083 bytes .../codemodernizer/testing_tool.patch | 838 ++++++++++++++++++ .../update_deprecated_api.patch | 14 + .../CodeWhispererCodeModernizerSessionTest.kt | 3 +- .../CodeWhispererCodeModernizerTest.kt | 6 +- .../CodeWhispererCodeModernizerTestBase.kt | 23 +- 16 files changed, 1095 insertions(+), 33 deletions(-) create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/diffPatchOutput.json create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/min_jdk_upgrade.patch create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/popular_enterprise_application_framework.patch create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/testing_tool.patch create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/update_deprecated_api.patch diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index ae3180be59a..e35b96afb4d 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -84,7 +84,6 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G private val downloadedSummaries = mutableMapOf() private val downloadedBuildLogPath = mutableMapOf() private var isCurrentlyDownloading = AtomicBoolean(false) -// private val scope = CoroutineScope(Dispatchers.Default) private var totalPatchFiles: Int = 0 @@ -292,22 +291,36 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G if (dialog.showAndGet()) { projectCoroutineScope(project).launch { telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) - if (getCurrentPatchIndex() < totalPatchFiles){ - val message = if (diffDescription != null) { - "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. ${patchDescriptions[diffDescription.name]}" - } else { - "I applied the changes to your project." - } + if (diffDescription == null) { + val message = "I applied the changes to your project." val resultContent = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.PendingAnswer, message = message, - buttons = listOf(createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/${totalPatchFiles}"), viewSummaryButton), ) codeTransformChatHelper?.updateLastPendingMessage(resultContent) - } else { codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) + } else { + if (getCurrentPatchIndex() < totalPatchFiles) { + val message = "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. " + + "${patchDescriptions[diffDescription.name]}" + setCurrentPatchIndex(getCurrentPatchIndex() + 1) + if (getCurrentPatchIndex() == totalPatchFiles) { + codeTransformChatHelper?.updateLastPendingMessage(CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message, + )) + } else { + codeTransformChatHelper?.updateLastPendingMessage(CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message, + buttons = listOf(createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/${totalPatchFiles}"), + viewSummaryButton), + )) + } + } else { + codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) + } } - setCurrentPatchIndex(getCurrentPatchIndex() + 1) } } else { telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Cancel", source) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index c96603b4917..4bd907f8ef2 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -428,14 +428,14 @@ fun buildTransformResultChatContent(result: CodeModernizerJobCompletedResult, to buildZipUploadFailedChatMessage(result.failureReason) } is CodeModernizerJobCompletedResult.JobCompletedSuccessfully -> { - if (totalPatchFiles == 1){ + if (totalPatchFiles == 1) { message("codemodernizer.chat.message.result.success") } else { message("codemodernizer.chat.message.result.success.multiple_diffs") } } is CodeModernizerJobCompletedResult.JobPartiallySucceeded -> { - if (totalPatchFiles == 1){ + if (totalPatchFiles == 1) { message("codemodernizer.chat.message.result.partially_success") } else { message("codemodernizer.chat.message.result.partially_success.multiple_diffs") diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index a6a85245c18..2225fec34b1 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -261,9 +261,12 @@ class CodeTransformChatController( override suspend fun processCodeTransformOneOrMultipleDiffs(message: IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs) { val transformCapabilities = when (message.oneOrMultipleDiffsSelection) { message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs") -> listOf( - EXPLAINABILITY_V1, SELECTIVE_TRANSFORMATION_V1) + EXPLAINABILITY_V1, + SELECTIVE_TRANSFORMATION_V1 + ) else -> listOf( - EXPLAINABILITY_V1) + EXPLAINABILITY_V1 + ) } codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection)) codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) @@ -539,8 +542,10 @@ class CodeTransformChatController( if (result is CodeModernizerJobCompletedResult.ZipUploadFailed && result.failureReason is UploadFailureReason.CREDENTIALS_EXPIRED) { return } else { - val downloadResult = artifactHandler.downloadArtifact(CodeModernizerSessionState.getInstance(context.project).currentJobId as JobId, - TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS) + val downloadResult = artifactHandler.downloadArtifact( + CodeModernizerSessionState.getInstance(context.project).currentJobId as JobId, + TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS + ) when (downloadResult) { is DownloadArtifactResult.Success -> { if (downloadResult.artifact !is CodeModernizerArtifact) return artifactHandler.notifyUnableToApplyPatch("") @@ -553,7 +558,6 @@ class CodeTransformChatController( is DownloadArtifactResult.Skipped -> {} is DownloadArtifactResult.UnzipFailure -> artifactHandler.notifyUnableToApplyPatch(downloadResult.failureReason.errorMessage) } - //codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) } } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index d8b4aa5f41a..293459eface 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -20,7 +20,6 @@ import kotlin.io.path.Path import kotlin.io.path.isDirectory import kotlin.io.path.walk - /** * Represents a CodeModernizer artifact. Essentially a wrapper around the manifest file in the downloaded artifact zip. */ @@ -39,7 +38,7 @@ open class CodeModernizerArtifact( private const val manifestPathInZip = "manifest.json" private const val summaryNameInZip = "summary.md" val LOG = getLogger() - private val MAPPER = jacksonObjectMapper() + val MAPPER = jacksonObjectMapper() /** * Extracts the file at [zipPath] and uses its contents to produce a [CodeModernizerArtifact]. @@ -117,6 +116,7 @@ open class CodeModernizerArtifact( } } } + @OptIn(ExperimentalPathApi::class) private fun extractSinglePatch(manifest: CodeModernizerManifest): List { val fileSystem = LocalFileSystem.getInstance() @@ -127,7 +127,6 @@ open class CodeModernizerArtifact( return patchesDir.walk() .map { fileSystem.refreshAndFindFileByNioFile(it) ?: throw RuntimeException("Could not find diff.patch") } .toList() - } @OptIn(ExperimentalPathApi::class) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt index a00d7238cc3..4eae0b4b9da 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerManifest.kt @@ -9,7 +9,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties data class CodeModernizerManifest(val version: Float, val patchesRoot: String, val artifactsRoot: String, val summaryRoot: String) @JsonIgnoreProperties(ignoreUnknown = true) -data class PatchInfo (val name: String, val filename: String, val isSuccessful: Boolean) +data class PatchInfo(val name: String, val filename: String, val isSuccessful: Boolean) @JsonIgnoreProperties(ignoreUnknown = true) -data class DescriptionContent (val content: List) +data class DescriptionContent(val content: List) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt index 7753bbf872a..c2635e95f64 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt @@ -27,7 +27,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.toolwindow.CodeMo import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactPomFolder import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilDependenciesRootDir import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilUploadZip -import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.resources.message import java.io.File import java.io.IOException @@ -206,7 +205,9 @@ data class CodeModernizerSessionContext( val outputFile = createTemporaryZipFile { zip -> // 1) Manifest file val dependenciesRoot = if (depDirectory != null) "$ZIP_DEPENDENCIES_PATH/${depDirectory.name}" else null - mapper.writeValueAsString(ZipManifest(dependenciesRoot = dependenciesRoot, transformCapabilities = transformCapabilities, customBuildCommand = customBuildCommand)) + mapper.writeValueAsString( + ZipManifest(dependenciesRoot = dependenciesRoot, transformCapabilities = transformCapabilities, customBuildCommand = customBuildCommand) + ) .byteInputStream() .use { zip.putNextEntry(Path(MANIFEST_PATH).toString(), it) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt index b951a87791f..a8c75345bea 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/state/CodeModernizerState.kt @@ -67,7 +67,7 @@ class CodeModernizerState : BaseState() { configurationFile, sourceJavaSdkVersion, targetJavaSdkVersion, - listOf(EXPLAINABILITY_V1), //default to one diff + listOf(EXPLAINABILITY_V1), // default to one diff lastJobContext[JobDetails.CUSTOM_BUILD_COMMAND] ?: MAVEN_BUILD_RUN_UNIT_TESTS // default to running unit tests ) } diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/diffPatchOutput.json b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/diffPatchOutput.json new file mode 100644 index 00000000000..5420780a66d --- /dev/null +++ b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/diffPatchOutput.json @@ -0,0 +1 @@ +{"content":[{"filename":"min_jdk_upgrade.patch","isSuccessful":false,"name":"Prepare minimal upgrade to Java 17"},{"filename":"popular_enterprise_application_framework.patch","isSuccessful":false,"name":"Popular Enterprise Specifications and Application Frameworks upgrade"},{"filename":"testing_tool.patch","isSuccessful":false,"name":"Testing Tools and Frameworks upgrade"},{"filename":"update_deprecated_api.patch","isSuccessful":false,"name":"Upgrade Deprecated API"}]} \ No newline at end of file diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/min_jdk_upgrade.patch b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/min_jdk_upgrade.patch new file mode 100644 index 00000000000..ac831101232 --- /dev/null +++ b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/min_jdk_upgrade.patch @@ -0,0 +1,161 @@ +diff --git a/pom.xml b/pom.xml +index bb3a51a..ff20499 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -5,24 +5,32 @@ + download-server + 0.0.1-SNAPSHOT + ++ 17 + UTF-8 + 4.1.1.RELEASE + + + org.springframework.boot + spring-boot-starter-parent +- 1.2.3.RELEASE ++ 3.3.5 + + ++ ++ ++ ++ org.codehaus.groovy ++ groovy-all ++ 2.4.16 ++ ++ ++ + + + + org.apache.maven.plugins + maven-compiler-plugin +- 3.0 + +- 1.8 +- 1.8 ++ ${java.version} + + + +@@ -48,7 +56,7 @@ + + org.springframework + spring-test +- 4.1.6.RELEASE ++ 6.1.15 + test + + +@@ -71,22 +79,18 @@ + + commons-codec + commons-codec +- 1.10 + + + org.springframework.boot + spring-boot-starter-web +- 1.2.3.RELEASE + + + org.springframework.boot + spring-boot-starter-actuator +- 1.2.3.RELEASE + + + org.springframework.boot + spring-boot-starter-test +- 1.2.3.RELEASE + + + org.springframework +@@ -100,6 +104,12 @@ + spock-core + 1.0-groovy-2.4 + test ++ ++ ++ junit ++ junit ++ ++ + + + com.google.guava +@@ -114,53 +124,46 @@ + + org.springframework + spring-beans +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-context +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-context-support +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-webmvc +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-web +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-aop +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-core +- 4.1.6.RELEASE ++ 6.1.15 + + + org.springframework + spring-expression +- 4.1.6.RELEASE +- +- +- org.springframework +- spring-test +- 4.1.6.RELEASE +- test ++ 6.1.15 + + + org.codehaus.groovy + groovy-all +- 2.4.3 + + + +diff --git a/src/main/java/com/nurkiewicz/download/MainApplication.java b/src/main/java/com/nurkiewicz/download/MainApplication.java +index 3bccd44..fe10ce1 100644 +--- a/src/main/java/com/nurkiewicz/download/MainApplication.java ++++ b/src/main/java/com/nurkiewicz/download/MainApplication.java +@@ -7,7 +7,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; + class MainApplication { + + public static void main(String[] args) { +- Integer temp = new Integer("1234"); ++ Integer temp = Integer.valueOf("1234"); + SpringApplication.run(MainApplication.class, args); + } + } diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/popular_enterprise_application_framework.patch b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/popular_enterprise_application_framework.patch new file mode 100644 index 00000000000..3290286ea4e --- /dev/null +++ b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/popular_enterprise_application_framework.patch @@ -0,0 +1,15 @@ +diff --git a/src/test/java/org/springframework/web/filter/Sha512ShallowEtagHeaderFilter.java b/src/test/java/org/springframework/web/filter/Sha512ShallowEtagHeaderFilter.java +index 50b2c90..8e9b1f8 100644 +--- a/src/test/java/org/springframework/web/filter/Sha512ShallowEtagHeaderFilter.java ++++ b/src/test/java/org/springframework/web/filter/Sha512ShallowEtagHeaderFilter.java +@@ -5,9 +5,9 @@ import com.google.common.hash.Hashing; + + public class Sha512ShallowEtagHeaderFilter extends ShallowEtagHeaderFilter { + +- @Override + protected String generateETagHeaderValue(byte[] bytes) { + final HashCode hash = Hashing.sha512().hashBytes(bytes); + return "\"" + hash + "\""; + } + } ++ diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip index 88f3ae39617830464db16ac0e025e8b752b52e89..61d3e4bb60f07b5171dfe6f64d7c7dab7d0c8b59 100644 GIT binary patch literal 42083 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 b(sw^NKMRKVpAIGl5CfcH)6`7bkNy7#lHn;J literal 1623 zcmWIWW@h1H0D;a$0pVZaLd4Xo+Cgx?Pr52ayWfkY=fsLuy8kP#eXvVC5 z7R11`bkmhZkIwwDQDxO;Rdu#yR+a52a7^+na?2_VsH^LoBsyg^|70H>t&=|9K6;Jb zhglzZb$J&T3wLWJaxI9dRn=>a0=oy|rzSK%u>svvkXVwO0rAfjpkMCd^UrRe{)vwb z>X?}r7}$V*6@cqc$xKVr0~-bQl2g5IstXXKd1-0T>AqVABC-Da9`USpP;+47>3QMd z@pe&`Y3S9+FMA8-NEb-wq*z}lJF@C_UF!ZN<~GZiw*)P<;y(Vp^xV$x&sJ#&91nh~ zXm#$?x!!u`1tP z`Sg3{ZeI9pQIyZx6P&H4#WvNSWRxp5|MYA-;nCH_y{Gbb9{27IS&^H|<0_toYUrMd ztz5HWN}8YflQ}bl)?KXdO3hR#+4o&>wasEJc5~yxM@KlQNOBm|LxzKQCe1O_x6zO%iZ^#{Fch|JzSV^Z^ra#XMg;B{99Y% zwD-~{&v{R-R87-cW4gM^Y2MZk%W`f0Bpvmc`OsYKWNilf??nk~IV2^!*yr{9tSaec zydPL%u*80&Zt0B`m!&!u$OZlN{&2A=ck(;oYX|>DvCDrrv@?V1iWqY8+HkW7G@ zq?ellPLP`0!csvPEkOo{ahyD%6UMN}rFGJoNpnKheK<3Tr}fdFJ0Y!;u5<~ldvRos z$buNZw79Z0Zf>5QjvJ@$tE;Ts8JCoo6k0bguBdL^J~i>_3+Fi*c=!ip`uSyf8cr9S zGJke_i@*~vhS{^{%%3#t04vbbj7)OOxXKj?Xb=c6ymbUIkxLm?NGXHnY>0Wd${2`w zz|x3eNuvvpL@RNCMq(*#ke!HGOdvb)3eZScp#d}tRA}IF9%hk&>^u>mD&2 ++ exit 1 ++ ) ++ pwd ++ )" ++fi ++ ++if [ -z "$JAVA_HOME" ]; then ++ javaExecutable="$(which javac)" ++ if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then ++ # readlink(1) is not available as standard on Solaris 10. ++ readLink=$(which readlink) ++ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then ++ if $darwin; then ++ javaHome="$(dirname "$javaExecutable")" ++ javaExecutable="$(cd "$javaHome" && pwd -P)/javac" ++ else ++ javaExecutable="$(readlink -f "$javaExecutable")" ++ fi ++ javaHome="$(dirname "$javaExecutable")" ++ javaHome=$(expr "$javaHome" : '\(.*\)/bin') ++ JAVA_HOME="$javaHome" ++ export JAVA_HOME ++ fi ++ fi ++fi ++ ++if [ -z "$JAVACMD" ]; then ++ if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" +- JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" +- JAVACCMD="$JAVA_HOME/bin/javac" +- +- if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then +- echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 +- echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 +- return 1 +- fi + fi + else + JAVACMD="$( +- 'set' +e +- 'unset' -f command 2>/dev/null +- 'command' -v java +- )" || : +- JAVACCMD="$( +- 'set' +e +- 'unset' -f command 2>/dev/null +- 'command' -v javac +- )" || : +- +- if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then +- echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 +- return 1 +- fi ++ \unset -f command 2>/dev/null ++ \command -v java ++ )" + fi +-} +- +-# hash string like Java String::hashCode +-hash_string() { +- str="${1:-}" h=0 +- while [ -n "$str" ]; do +- char="${str%"${str#?}"}" +- h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) +- str="${str#?}" +- done +- printf %x\\n $h +-} +- +-verbose() { :; } +-[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } ++fi + +-die() { +- printf %s\\n "$1" >&2 ++if [ ! -x "$JAVACMD" ]; then ++ echo "Error: JAVA_HOME is not defined correctly." >&2 ++ echo " We cannot execute $JAVACMD" >&2 + exit 1 +-} ++fi + +-trim() { +- # MWRAPPER-139: +- # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. +- # Needed for removing poorly interpreted newline sequences when running in more +- # exotic environments such as mingw bash on Windows. +- printf "%s" "${1}" | tr -d '[:space:]' +-} ++if [ -z "$JAVA_HOME" ]; then ++ echo "Warning: JAVA_HOME environment variable is not set." >&2 ++fi + +-# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +-while IFS="=" read -r key value; do +- case "${key-}" in +- distributionUrl) distributionUrl=$(trim "${value-}") ;; +- distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; +- esac +-done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +-[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" ++# traverses directory structure from process work directory to filesystem root ++# first directory with .mvn subdirectory is considered project base directory ++find_maven_basedir() { ++ if [ -z "$1" ]; then ++ echo "Path not specified to find_maven_basedir" >&2 ++ return 1 ++ fi + +-case "${distributionUrl##*/}" in +-maven-mvnd-*bin.*) +- MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ +- case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in +- *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; +- :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; +- :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; +- :Linux*x86_64*) distributionPlatform=linux-amd64 ;; +- *) +- echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 +- distributionPlatform=linux-amd64 +- ;; +- esac +- distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" +- ;; +-maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +-*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +-esac ++ basedir="$1" ++ wdir="$1" ++ while [ "$wdir" != '/' ]; do ++ if [ -d "$wdir"/.mvn ]; then ++ basedir=$wdir ++ break ++ fi ++ # workaround for JBEAP-8937 (on Solaris 10/Sparc) ++ if [ -d "${wdir}" ]; then ++ wdir=$( ++ cd "$wdir/.." || exit 1 ++ pwd ++ ) ++ fi ++ # end of workaround ++ done ++ printf '%s' "$( ++ cd "$basedir" || exit 1 ++ pwd ++ )" ++} + +-# apply MVNW_REPOURL and calculate MAVEN_HOME +-# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +-[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +-distributionUrlName="${distributionUrl##*/}" +-distributionUrlNameMain="${distributionUrlName%.*}" +-distributionUrlNameMain="${distributionUrlNameMain%-bin}" +-MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +-MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" ++# concatenates all lines of a file ++concat_lines() { ++ if [ -f "$1" ]; then ++ # Remove \r in case we run on Windows within Git Bash ++ # and check out the repository with auto CRLF management ++ # enabled. Otherwise, we may read lines that are delimited with ++ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word ++ # splitting rules. ++ tr -s '\r\n' ' ' <"$1" ++ fi ++} + +-exec_maven() { +- unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : +- exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" ++log() { ++ if [ "$MVNW_VERBOSE" = true ]; then ++ printf '%s\n' "$1" ++ fi + } + +-if [ -d "$MAVEN_HOME" ]; then +- verbose "found existing MAVEN_HOME at $MAVEN_HOME" +- exec_maven "$@" ++BASE_DIR=$(find_maven_basedir "$(dirname "$0")") ++if [ -z "$BASE_DIR" ]; then ++ exit 1 + fi + +-case "${distributionUrl-}" in +-*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +-*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +-esac ++MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} ++export MAVEN_PROJECTBASEDIR ++log "$MAVEN_PROJECTBASEDIR" + +-# prepare tmp dir +-if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then +- clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } +- trap clean HUP INT TERM EXIT ++########################################################################################## ++# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central ++# This allows using the maven wrapper in projects that prohibit checking in binary data. ++########################################################################################## ++wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" ++if [ -r "$wrapperJarPath" ]; then ++ log "Found $wrapperJarPath" + else +- die "cannot create temp dir" +-fi +- +-mkdir -p -- "${MAVEN_HOME%/*}" ++ log "Couldn't find $wrapperJarPath, downloading it ..." + +-# Download and Install Apache Maven +-verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +-verbose "Downloading from: $distributionUrl" +-verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" +- +-# select .zip or .tar.gz +-if ! command -v unzip >/dev/null; then +- distributionUrl="${distributionUrl%.zip}.tar.gz" +- distributionUrlName="${distributionUrl##*/}" +-fi +- +-# verbose opt +-__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +-[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v ++ if [ -n "$MVNW_REPOURL" ]; then ++ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" ++ else ++ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" ++ fi ++ while IFS="=" read -r key value; do ++ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) ++ safeValue=$(echo "$value" | tr -d '\r') ++ case "$key" in wrapperUrl) ++ wrapperUrl="$safeValue" ++ break ++ ;; ++ esac ++ done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" ++ log "Downloading from: $wrapperUrl" + +-# normalize http auth +-case "${MVNW_PASSWORD:+has-password}" in +-'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +-has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +-esac ++ if $cygwin; then ++ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") ++ fi + +-if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then +- verbose "Found wget ... using wget" +- wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +-elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then +- verbose "Found curl ... using curl" +- curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +-elif set_java_home; then +- verbose "Falling back to use Java to download" +- javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" +- targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" +- cat >"$javaSource" <<-END +- public class Downloader extends java.net.Authenticator +- { +- protected java.net.PasswordAuthentication getPasswordAuthentication() +- { +- return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); +- } +- public static void main( String[] args ) throws Exception +- { +- setDefault( new Downloader() ); +- java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); +- } +- } +- END +- # For Cygwin/MinGW, switch paths to Windows format before running javac and java +- verbose " - Compiling Downloader.java ..." +- "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" +- verbose " - Running Downloader.java ..." +- "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" ++ if command -v wget >/dev/null; then ++ log "Found wget ... using wget" ++ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" ++ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then ++ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" ++ else ++ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" ++ fi ++ elif command -v curl >/dev/null; then ++ log "Found curl ... using curl" ++ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" ++ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then ++ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" ++ else ++ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" ++ fi ++ else ++ log "Falling back to using Java to download" ++ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" ++ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" ++ # For Cygwin, switch paths to Windows format before running javac ++ if $cygwin; then ++ javaSource=$(cygpath --path --windows "$javaSource") ++ javaClass=$(cygpath --path --windows "$javaClass") ++ fi ++ if [ -e "$javaSource" ]; then ++ if [ ! -e "$javaClass" ]; then ++ log " - Compiling MavenWrapperDownloader.java ..." ++ ("$JAVA_HOME/bin/javac" "$javaSource") ++ fi ++ if [ -e "$javaClass" ]; then ++ log " - Running MavenWrapperDownloader.java ..." ++ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" ++ fi ++ fi ++ fi + fi ++########################################################################################## ++# End of extension ++########################################################################################## + +-# If specified, validate the SHA-256 sum of the Maven distribution zip file +-if [ -n "${distributionSha256Sum-}" ]; then +- distributionSha256Result=false +- if [ "$MVN_CMD" = mvnd.sh ]; then +- echo "Checksum validation is not supported for maven-mvnd." >&2 +- echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 +- exit 1 +- elif command -v sha256sum >/dev/null; then +- if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then +- distributionSha256Result=true ++# If specified, validate the SHA-256 sum of the Maven wrapper jar file ++wrapperSha256Sum="" ++while IFS="=" read -r key value; do ++ case "$key" in wrapperSha256Sum) ++ wrapperSha256Sum=$value ++ break ++ ;; ++ esac ++done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" ++if [ -n "$wrapperSha256Sum" ]; then ++ wrapperSha256Result=false ++ if command -v sha256sum >/dev/null; then ++ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then ++ wrapperSha256Result=true + fi + elif command -v shasum >/dev/null; then +- if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then +- distributionSha256Result=true ++ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then ++ wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 +- echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 ++ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi +- if [ $distributionSha256Result = false ]; then +- echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 +- echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 ++ if [ $wrapperSha256Result = false ]; then ++ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 ++ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 ++ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi + fi + +-# unzip and move +-if command -v unzip >/dev/null; then +- unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +-else +- tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" ++MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" ++ ++# For Cygwin, switch paths to Windows format before running java ++if $cygwin; then ++ [ -n "$JAVA_HOME" ] \ ++ && JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") ++ [ -n "$CLASSPATH" ] \ ++ && CLASSPATH=$(cygpath --path --windows "$CLASSPATH") ++ [ -n "$MAVEN_PROJECTBASEDIR" ] \ ++ && MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") + fi +-printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +-mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +-clean || : +-exec_maven "$@" ++# Provide a "standardized" way to retrieve the CLI args that will ++# work with both Windows and non-Windows executions. ++MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" ++export MAVEN_CMD_LINE_ARGS ++ ++WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain ++ ++# shellcheck disable=SC2086 # safe args ++exec "$JAVACMD" \ ++ $MAVEN_OPTS \ ++ $MAVEN_DEBUG_OPTS \ ++ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ ++ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ++ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +diff --git a/mvnw.cmd b/mvnw.cmd +old mode 100644 +new mode 100755 +index b150b91..1204076 +--- a/mvnw.cmd ++++ b/mvnw.cmd +@@ -1,4 +1,3 @@ +-<# : batch portion + @REM ---------------------------------------------------------------------------- + @REM Licensed to the Apache Software Foundation (ASF) under one + @REM or more contributor license agreements. See the NOTICE file +@@ -21,129 +20,187 @@ + @REM ---------------------------------------------------------------------------- + @REM Apache Maven Wrapper startup batch script, version 3.3.2 + @REM ++@REM Required ENV vars: ++@REM JAVA_HOME - location of a JDK home dir ++@REM + @REM Optional ENV vars +-@REM MVNW_REPOURL - repo url base for downloading maven distribution +-@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +-@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output ++@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands ++@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending ++@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven ++@REM e.g. to debug Maven itself, use ++@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 ++@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files + @REM ---------------------------------------------------------------------------- + +-@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +-@SET __MVNW_CMD__= +-@SET __MVNW_ERROR__= +-@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +-@SET PSModulePath= +-@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( +- IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ++@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' ++@echo off ++@REM set title of command window ++title %0 ++@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' ++@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% ++ ++@REM set %HOME% to equivalent of $HOME ++if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") ++ ++@REM Execute a user defined script before this one ++if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre ++@REM check for pre script, once with legacy .bat ending and once with .cmd ending ++if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* ++if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* ++:skipRcPre ++ ++@setlocal ++ ++set ERROR_CODE=0 ++ ++@REM To isolate internal variables from possible post scripts, we use another setlocal ++@setlocal ++ ++@REM ==== START VALIDATION ==== ++if not "%JAVA_HOME%" == "" goto OkJHome ++ ++echo. >&2 ++echo Error: JAVA_HOME not found in your environment. >&2 ++echo Please set the JAVA_HOME variable in your environment to match the >&2 ++echo location of your Java installation. >&2 ++echo. >&2 ++goto error ++ ++:OkJHome ++if exist "%JAVA_HOME%\bin\java.exe" goto init ++ ++echo. >&2 ++echo Error: JAVA_HOME is set to an invalid directory. >&2 ++echo JAVA_HOME = "%JAVA_HOME%" >&2 ++echo Please set the JAVA_HOME variable in your environment to match the >&2 ++echo location of your Java installation. >&2 ++echo. >&2 ++goto error ++ ++@REM ==== END VALIDATION ==== ++ ++:init ++ ++@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". ++@REM Fallback to current working directory if not found. ++ ++set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% ++IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir ++ ++set EXEC_DIR=%CD% ++set WDIR=%EXEC_DIR% ++:findBaseDir ++IF EXIST "%WDIR%"\.mvn goto baseDirFound ++cd .. ++IF "%WDIR%"=="%CD%" goto baseDirNotFound ++set WDIR=%CD% ++goto findBaseDir ++ ++:baseDirFound ++set MAVEN_PROJECTBASEDIR=%WDIR% ++cd "%EXEC_DIR%" ++goto endDetectBaseDir ++ ++:baseDirNotFound ++set MAVEN_PROJECTBASEDIR=%EXEC_DIR% ++cd "%EXEC_DIR%" ++ ++:endDetectBaseDir ++ ++IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig ++ ++@setlocal EnableExtensions EnableDelayedExpansion ++for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a ++@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% ++ ++:endReadAdditionalConfig ++ ++SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" ++set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" ++set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain ++ ++set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" ++ ++FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( ++ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B ++) ++ ++@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central ++@REM This allows using the maven wrapper in projects that prohibit checking in binary data. ++if exist %WRAPPER_JAR% ( ++ if "%MVNW_VERBOSE%" == "true" ( ++ echo Found %WRAPPER_JAR% ++ ) ++) else ( ++ if not "%MVNW_REPOURL%" == "" ( ++ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" ++ ) ++ if "%MVNW_VERBOSE%" == "true" ( ++ echo Couldn't find %WRAPPER_JAR%, downloading it ... ++ echo Downloading from: %WRAPPER_URL% ++ ) ++ ++ powershell -Command "&{"^ ++ "$webclient = new-object System.Net.WebClient;"^ ++ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ ++ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ ++ "}"^ ++ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ ++ "}" ++ if "%MVNW_VERBOSE%" == "true" ( ++ echo Finished downloading %WRAPPER_JAR% ++ ) ++) ++@REM End of extension ++ ++@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file ++SET WRAPPER_SHA_256_SUM="" ++FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( ++ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B + ) +-@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +-@SET __MVNW_PSMODULEP_SAVE= +-@SET __MVNW_ARG0_NAME__= +-@SET MVNW_USERNAME= +-@SET MVNW_PASSWORD= +-@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +-@echo Cannot start maven from wrapper >&2 && exit /b 1 +-@GOTO :EOF +-: end batch / begin powershell #> +- +-$ErrorActionPreference = "Stop" +-if ($env:MVNW_VERBOSE -eq "true") { +- $VerbosePreference = "Continue" +-} +- +-# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +-$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +-if (!$distributionUrl) { +- Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +-} +- +-switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { +- "maven-mvnd-*" { +- $USE_MVND = $true +- $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" +- $MVN_CMD = "mvnd.cmd" +- break +- } +- default { +- $USE_MVND = $false +- $MVN_CMD = $script -replace '^mvnw','mvn' +- break +- } +-} +- +-# apply MVNW_REPOURL and calculate MAVEN_HOME +-# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +-if ($env:MVNW_REPOURL) { +- $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } +- $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +-} +-$distributionUrlName = $distributionUrl -replace '^.*/','' +-$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +-$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +-if ($env:MAVEN_USER_HOME) { +- $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +-} +-$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +-$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" +- +-if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { +- Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" +- Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" +- exit $? +-} +- +-if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { +- Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +-} +- +-# prepare tmp dir +-$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +-$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +-$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +-trap { +- if ($TMP_DOWNLOAD_DIR.Exists) { +- try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } +- catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +- } +-} +- +-New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null +- +-# Download and Install Apache Maven +-Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +-Write-Verbose "Downloading from: $distributionUrl" +-Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" +- +-$webclient = New-Object System.Net.WebClient +-if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { +- $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +-} +-[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +-$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null +- +-# If specified, validate the SHA-256 sum of the Maven distribution zip file +-$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +-if ($distributionSha256Sum) { +- if ($USE_MVND) { +- Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." +- } +- Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash +- if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { +- Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." +- } +-} +- +-# unzip and move +-Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +-Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +-try { +- Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +-} catch { +- if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { +- Write-Error "fail to move MAVEN_HOME" +- } +-} finally { +- try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } +- catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +-} +- +-Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" ++IF NOT %WRAPPER_SHA_256_SUM%=="" ( ++ powershell -Command "&{"^ ++ "Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^ ++ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ ++ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ ++ " Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ ++ " Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ ++ " Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ ++ " exit 1;"^ ++ "}"^ ++ "}" ++ if ERRORLEVEL 1 goto error ++) ++ ++@REM Provide a "standardized" way to retrieve the CLI args that will ++@REM work with both Windows and non-Windows executions. ++set MAVEN_CMD_LINE_ARGS=%* ++ ++%MAVEN_JAVA_EXE% ^ ++ %JVM_CONFIG_MAVEN_PROPS% ^ ++ %MAVEN_OPTS% ^ ++ %MAVEN_DEBUG_OPTS% ^ ++ -classpath %WRAPPER_JAR% ^ ++ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ ++ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* ++if ERRORLEVEL 1 goto error ++goto end ++ ++:error ++set ERROR_CODE=1 ++ ++:end ++@endlocal & set ERROR_CODE=%ERROR_CODE% ++ ++if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost ++@REM check for post script, once with legacy .bat ending and once with .cmd ending ++if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" ++if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" ++:skipRcPost ++ ++@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' ++if "%MAVEN_BATCH_PAUSE%"=="on" pause ++ ++if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% ++ ++cmd /C exit /B %ERROR_CODE% diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/update_deprecated_api.patch b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/update_deprecated_api.patch new file mode 100644 index 00000000000..42ea73fdc7f --- /dev/null +++ b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/update_deprecated_api.patch @@ -0,0 +1,14 @@ +diff --git a/pom.xml b/pom.xml +index ff20499..7f6c83b 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -8,6 +8,9 @@ + 17 + UTF-8 + 4.1.1.RELEASE ++ 17 ++ 17 ++ 17 + + + org.springframework.boot diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt index 0d921f8b323..a4017d742d1 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt @@ -144,7 +144,8 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa assertFalse(roots.isEmpty() || roots.size > 1) assert(rootManager.dependencies.isEmpty()) val root = roots[0] - val context = CodeModernizerSessionContext(project, root.children[0], JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11, MAVEN_BUILD_SKIP_UNIT_TESTS) + val context = CodeModernizerSessionContext(project, root.children[0], JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11, + listOf(EXPLAINABILITY_V1, SELECTIVE_TRANSFORMATION_V1), MAVEN_BUILD_SKIP_UNIT_TESTS) val mockFile = mock(File::class.java) val mockStringBuilder = mock(StringBuilder::class.java) val file = runInEdtAndGet { diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt index 0f657f2d278..ff06ae946bf 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt @@ -128,10 +128,10 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { val path = testCodeModernizerArtifact.zipPath val result = DownloadArtifactResult.Success(testCodeModernizerArtifact, path) doReturn(result).whenever(handler).downloadArtifact(any(), eq(TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS), eq(false)) - doNothing().whenever(handler).displayDiffUsingPatch(any(), any(), any()) handler.displayDiff(jobId, CodeTransformVCSViewerSrcComponents.Chat) verify(handler, never()).notifyUnableToApplyPatch(any()) - verify(handler, times(1)).displayDiffUsingPatch(testCodeModernizerArtifact.patch, jobId, CodeTransformVCSViewerSrcComponents.Chat) + verify(handler, times(1)).displayDiffUsingPatch(testCodeModernizerArtifact.patches[0], testCodeModernizerArtifact.patches.size, + testCodeModernizerArtifact.description?.get(0), jobId, CodeTransformVCSViewerSrcComponents.Chat) } @Test @@ -154,8 +154,8 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { @Test fun `CodeModernizerArtifact can process a valid zip file`() { val artifact = CodeModernizerArtifact.create(exampleZipPath.toAbsolutePath().toString()) + assertEquals(4, artifact.patches.size) assertEquals(validManifest, artifact.manifest) - assertEquals(validTransformationSummary, artifact.summary) } @Test diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt index 8b489b74d8d..1de4d0f6aa9 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt @@ -51,10 +51,12 @@ import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAu import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact +import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact.Companion.MAPPER import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerManifest import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerSessionContext import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformFailureBuildLog import software.aws.toolkits.jetbrains.services.codemodernizer.model.CustomerSelection +import software.aws.toolkits.jetbrains.services.codemodernizer.model.DescriptionContent import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.panels.managers.CodeModernizerBottomWindowPanelManager import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState @@ -87,8 +89,17 @@ open class CodeWhispererCodeModernizerTestBase( lateinit var testModernizerBottomWindowPanelSpy: CodeModernizerBottomWindowPanelManager internal lateinit var testSessionSpy: CodeModernizerSession internal lateinit var testSessionStateSpy: CodeModernizerSessionState - internal val diffResource = "diff.patch".toResourceFile() - internal val examplePatchVirtualFile = LightVirtualFile("diff.patch", diffResource.readText()) + internal val minJDKUpgradePatchResource = "min_jdk_upgrade.patch".toResourceFile() + internal val minJDKUpgradePatchResourceFile = LightVirtualFile("min_jdk_upgrade.patch", minJDKUpgradePatchResource.readText()) + internal val enterpriseApplicationUpgradePatchResource = "popular_enterprise_application_framework.patch".toResourceFile() + internal val enterpriseApplicationUpgradePatchResourceFile = LightVirtualFile("popular_enterprise_application_framework.patch", + enterpriseApplicationUpgradePatchResource.readText()) + internal val testingToolPatchResource = "testing_tool.patch".toResourceFile() + internal val testingToolPatchResourceFile = LightVirtualFile("testing_tool.patch", testingToolPatchResource.readText()) + internal val deprecatedAPIPatchResource = "update_deprecated_api.patch".toResourceFile() + internal val deprecatedAPIPatchResourceFile = LightVirtualFile("update_deprecated_api.patch", deprecatedAPIPatchResource.readText()) + internal val diffJsonResource = "diffPatchOutput.json".toResourceFile() + internal val exampleDescriptionContent: DescriptionContent = MAPPER.readValue(diffJsonResource, DescriptionContent::class.java) internal val emptyPomFile = LightVirtualFile("pom.xml", "") internal val emptyPomFileSpy = spy(emptyPomFile) internal val jobId = JobId("Test job id") @@ -268,7 +279,9 @@ open class CodeWhispererCodeModernizerTestBase( val summaryFileMock = Mockito.mock(File::class.java) val logFileMock = Mockito.mock(File::class.java) doReturn("dummy/path").whenever(virtualFileMock).path - testSessionContextSpy = spy(CodeModernizerSessionContext(project, virtualFileMock, JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11, "test")) + testSessionContextSpy = spy(CodeModernizerSessionContext(project, virtualFileMock, JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11, + listOf("EXPLAINABILITY_V1", "SELECTIVE_TRANSFORMATION_V1"), "test")) + testSessionSpy = spy(CodeModernizerSession(testSessionContextSpy, 0, 0)) doNothing().whenever(testSessionSpy).deleteUploadArtifact(any()) doReturn(Job()).whenever(codeModernizerManagerSpy).launchModernizationJob(any(), any()) @@ -277,7 +290,9 @@ open class CodeWhispererCodeModernizerTestBase( CodeModernizerArtifact( exampleZipPath.toAbsolutePath().toString(), validManifest, - listOf(examplePatchVirtualFile), + listOf(minJDKUpgradePatchResourceFile, enterpriseApplicationUpgradePatchResourceFile, + testingToolPatchResourceFile, deprecatedAPIPatchResourceFile), + exampleDescriptionContent.content, validTransformationSummary, summaryFileMock, ), From 89a8bb53b30ff6543f455c657a27443c277a965d Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Mon, 18 Nov 2024 13:20:43 -0800 Subject: [PATCH 11/19] adding test zip --- .../codemodernizer/{simple.zip => sample-diff.zip} | Bin .../CodeWhispererCodeModernizerTestBase.kt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/{simple.zip => sample-diff.zip} (100%) diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip similarity index 100% rename from plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip rename to plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt index 1de4d0f6aa9..09f47c8b7b2 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt @@ -105,7 +105,7 @@ open class CodeWhispererCodeModernizerTestBase( internal val jobId = JobId("Test job id") internal lateinit var testCodeModernizerArtifact: CodeModernizerArtifact internal lateinit var testTransformFailureBuildLog: CodeTransformFailureBuildLog - internal val exampleZipPath = "simple.zip".toResourceFile().toPath() + internal val exampleZipPath = "sample-diff.zip".toResourceFile().toPath() internal val expectedFilePath = "expectedFile".toResourceFile().toPath() internal val overwrittenFilePath = "overwrittenFile".toResourceFile().toPath() internal val testRequestId = "test_aws_request_id" From a667cc4472eb5daff576b1c93c51fa720294788a Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Mon, 18 Nov 2024 13:23:52 -0800 Subject: [PATCH 12/19] removing sample diff zip --- .../codemodernizer/sample-diff.zip | Bin 42083 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip deleted file mode 100644 index 61d3e4bb60f07b5171dfe6f64d7c7dab7d0c8b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42083 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 b(sw^NKMRKVpAIGl5CfcH)6`7bkNy7#lHn;J From 1a1fdb8283f2a1079f01e0da10a31594c8fe202d Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Mon, 18 Nov 2024 13:24:48 -0800 Subject: [PATCH 13/19] adding sample diff zip --- .../codemodernizer/sample-diff.zip | Bin 0 -> 42083 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip new file mode 100644 index 0000000000000000000000000000000000000000..61d3e4bb60f07b5171dfe6f64d7c7dab7d0c8b59 GIT binary patch literal 42083 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 b(sw^NKMRKVpAIGl5CfcH)6`7bkNy7#lHn;J literal 0 HcmV?d00001 From 77fb5b9b0241dd319fc3a03bfb8830f2dcc0563c Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Mon, 18 Nov 2024 13:29:48 -0800 Subject: [PATCH 14/19] adding simple back --- .../codemodernizer/sample-diff.zip | Bin 42083 -> 0 bytes .../tst-resources/codemodernizer/simple.zip | Bin 0 -> 24241 bytes .../CodeWhispererCodeModernizerTestBase.kt | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/sample-diff.zip deleted file mode 100644 index 61d3e4bb60f07b5171dfe6f64d7c7dab7d0c8b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42083 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 b(sw^NKMRKVpAIGl5CfcH)6`7bkNy7#lHn;J diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/simple.zip new file mode 100644 index 0000000000000000000000000000000000000000..0d7bc0cdef52b93ce74841c6969bead32eb5249d GIT binary patch literal 24241 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 literal 0 HcmV?d00001 diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt index 09f47c8b7b2..1de4d0f6aa9 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt @@ -105,7 +105,7 @@ open class CodeWhispererCodeModernizerTestBase( internal val jobId = JobId("Test job id") internal lateinit var testCodeModernizerArtifact: CodeModernizerArtifact internal lateinit var testTransformFailureBuildLog: CodeTransformFailureBuildLog - internal val exampleZipPath = "sample-diff.zip".toResourceFile().toPath() + internal val exampleZipPath = "simple.zip".toResourceFile().toPath() internal val expectedFilePath = "expectedFile".toResourceFile().toPath() internal val overwrittenFilePath = "overwrittenFile".toResourceFile().toPath() internal val testRequestId = "test_aws_request_id" From f2ff3d4e0540f9108fd27c274b61956bfbd47894 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Tue, 19 Nov 2024 09:28:39 -0800 Subject: [PATCH 15/19] fixing detekt and adding patch applied notification and updating unit tests --- .../codemodernizer/ArtifactHandler.kt | 63 +++++++++++------- .../codemodernizer/CodeModernizerSession.kt | 1 - .../constants/CodeTransformChatItems.kt | 10 +-- .../controller/CodeTransformChatController.kt | 4 +- .../model/CodeModernizerArtifact.kt | 1 - .../codemodernizer/multiple-diff.zip | Bin 0 -> 42083 bytes .../CodeWhispererCodeModernizerSessionTest.kt | 10 ++- .../CodeWhispererCodeModernizerTest.kt | 27 +++++++- .../CodeWhispererCodeModernizerTestBase.kt | 19 +++++- 9 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/multiple-diff.zip diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index 8923680931d..bfa0fc67f2e 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -15,6 +15,11 @@ import com.intellij.openapi.vcs.changes.patch.ApplyPatchMode import com.intellij.openapi.vcs.changes.patch.ImportToShelfExecutor import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.time.Instant +import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType @@ -30,8 +35,9 @@ import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESH import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_EXPIRED import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.getDownloadedArtifactTextFromType +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup import software.aws.toolkits.jetbrains.services.codemodernizer.constants.createViewDiffButton +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.getDownloadedArtifactTextFromType import software.aws.toolkits.jetbrains.services.codemodernizer.constants.viewSummaryButton import software.aws.toolkits.jetbrains.services.codemodernizer.controller.CodeTransformChatHelper import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessageContent @@ -54,12 +60,6 @@ import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformArtifactType import software.aws.toolkits.telemetry.CodeTransformVCSViewerSrcComponents -import java.io.File -import java.nio.file.Files -import java.nio.file.Path -import java.time.Instant -import java.util.concurrent.atomic.AtomicBoolean -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildStartNewTransformFollowup const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0" const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request: javax.net.ssl.SSLHandshakeException" @@ -78,8 +78,11 @@ val patchDescriptions: Map = mapOf( "Upgrade Deprecated API" to "" ) -class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient, - private val codeTransformChatHelper: CodeTransformChatHelper? = null) { +class ArtifactHandler( + private val project: Project, + private val clientAdaptor: GumbyClient, + private val codeTransformChatHelper: CodeTransformChatHelper? = null, +) { private val telemetry = CodeTransformTelemetryManager.getInstance(project) private val downloadedArtifacts = mutableMapOf() private val downloadedSummaries = mutableMapOf() @@ -87,14 +90,13 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G private var isCurrentlyDownloading = AtomicBoolean(false) private var totalPatchFiles: Int = 0 - internal suspend fun displayDiff(job: JobId, source: CodeTransformVCSViewerSrcComponents) { if (isCurrentlyDownloading.get()) return when (val result = downloadArtifact(job, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS)) { is DownloadArtifactResult.Success -> { if (result.artifact !is CodeModernizerArtifact) return notifyUnableToApplyPatch("") totalPatchFiles = result.artifact.patches.size - if (result.artifact.description == null){ + if (result.artifact.description == null) { displayDiffUsingPatch(result.artifact.patches.first(), totalPatchFiles, null, job, source) } else { val diffDescription = result.artifact.description[getCurrentPatchIndex()] @@ -275,8 +277,13 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G /** * Opens the built-in patch dialog to display the diff and allowing users to apply the changes locally. */ - internal suspend fun displayDiffUsingPatch(patchFile: VirtualFile, totalPatchFiles: Int, diffDescription: PatchInfo?, jobId: JobId, - source: CodeTransformVCSViewerSrcComponents) { + internal fun displayDiffUsingPatch( + patchFile: VirtualFile, + totalPatchFiles: Int, + diffDescription: PatchInfo?, + jobId: JobId, + source: CodeTransformVCSViewerSrcComponents, + ) { runInEdt { val dialog = ApplyPatchDifferentiatedDialog( project, @@ -292,7 +299,8 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G } else { patchFile.name }, - ""), + "" + ), null, null, null, @@ -315,19 +323,26 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G if (getCurrentPatchIndex() < totalPatchFiles) { val message = "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. " + "${patchDescriptions[diffDescription.name]}" + val notificationMessage = "Amazon Q applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles " + + "to your project." + val notificationTitle = "Diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles applied" setCurrentPatchIndex(getCurrentPatchIndex() + 1) + notifyStickyInfo(notificationTitle, notificationMessage, project) if (getCurrentPatchIndex() == totalPatchFiles) { - codeTransformChatHelper?.updateLastPendingMessage(CodeTransformChatMessageContent( - type = CodeTransformChatMessageType.PendingAnswer, - message = message, - )) + codeTransformChatHelper?.updateLastPendingMessage( + CodeTransformChatMessageContent(type = CodeTransformChatMessageType.PendingAnswer, message = message) + ) } else { - codeTransformChatHelper?.updateLastPendingMessage(CodeTransformChatMessageContent( - type = CodeTransformChatMessageType.PendingAnswer, - message = message, - buttons = listOf(createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/${totalPatchFiles}"), - viewSummaryButton), - )) + codeTransformChatHelper?.updateLastPendingMessage( + CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message, + buttons = listOf( + createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/$totalPatchFiles"), + viewSummaryButton + ) + ) + ) } } else { codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt index b5d0b90a5e3..0e9d3b1ebc2 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt @@ -63,7 +63,6 @@ import java.util.concurrent.atomic.AtomicBoolean import javax.net.ssl.SSLHandshakeException const val MAX_ZIP_SIZE = 2000000000 // 2GB -const val HIL_1P_UPGRADE_CAPABILITY = "HIL_1pDependency_VersionUpgrade" const val EXPLAINABILITY_V1 = "EXPLAINABILITY_V1" const val SELECTIVE_TRANSFORMATION_V1 = "SELECTIVE_TRANSFORMATION_V1" diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt index cf8982c18e2..8a8358c41b6 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt @@ -102,9 +102,11 @@ private val viewDiffButton = Button( keepCardAfterClick = true, ) -fun createViewDiffButton(buttonLabel: String): Button { - return Button(id = CodeTransformButtonId.ViewDiff.id, text = buttonLabel, keepCardAfterClick = true) -} +fun createViewDiffButton(buttonLabel: String): Button = Button( + id = CodeTransformButtonId.ViewDiff.id, + text = buttonLabel, + keepCardAfterClick = true +) val viewSummaryButton = Button( id = CodeTransformButtonId.ViewSummary.id, @@ -587,7 +589,7 @@ fun buildTransformResultChatContent(result: CodeModernizerJobCompletedResult, to type = CodeTransformChatMessageType.FinalizedAnswer, message = resultMessage, buttons = if (result is CodeModernizerJobCompletedResult.JobPartiallySucceeded || result is CodeModernizerJobCompletedResult.JobCompletedSuccessfully) { - listOf(createViewDiffButton(if (totalPatchFiles == 1) "View diff" else "View diff 1/${totalPatchFiles}"), viewSummaryButton) + listOf(createViewDiffButton(if (totalPatchFiles == 1) "View diff" else "View diff 1/$totalPatchFiles"), viewSummaryButton) } else if (result is CodeModernizerJobCompletedResult.JobFailedInitialBuild && result.hasBuildLog) { listOf(viewBuildLog) } else { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index 0b3a61a1fb2..d30897f99f8 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -13,8 +13,8 @@ import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.VirtualFile import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking -import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import kotlinx.coroutines.withContext +import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.getLogger @@ -29,7 +29,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTele import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.HilTelemetryMetaData import software.aws.toolkits.jetbrains.services.codemodernizer.InboundAppMessagesHandler -import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFORMATION_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformActionMessage import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformCommand @@ -99,6 +98,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenDepend import software.aws.toolkits.jetbrains.services.codemodernizer.model.UploadFailureReason import software.aws.toolkits.jetbrains.services.codemodernizer.model.ValidationResult import software.aws.toolkits.jetbrains.services.codemodernizer.panels.managers.CodeModernizerBottomWindowPanelManager +import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFORMATION_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.session.ChatSessionStorage import software.aws.toolkits.jetbrains.services.codemodernizer.session.Session import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index 890a6ca3b57..f209e2b0ffc 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -150,7 +150,6 @@ open class CodeModernizerArtifact( .toList() } - @OptIn(ExperimentalPathApi::class) private fun loadDescription(manifest: CodeModernizerManifest): List? { val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot).toFile() if (!patchesDir.isDirectory) { diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/multiple-diff.zip b/plugins/amazonq/codetransform/jetbrains-community/tst-resources/codemodernizer/multiple-diff.zip new file mode 100644 index 0000000000000000000000000000000000000000..61d3e4bb60f07b5171dfe6f64d7c7dab7d0c8b59 GIT binary patch literal 42083 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 b(sw^NKMRKVpAIGl5CfcH)6`7bkNy7#lHn;J literal 0 HcmV?d00001 diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt index d5e1fc7bb63..f50e5e9c737 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt @@ -145,8 +145,14 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa assertFalse(roots.isEmpty() || roots.size > 1) assert(rootManager.dependencies.isEmpty()) val root = roots[0] - val context = CodeModernizerSessionContext(project, root.children[0], JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11, - listOf(EXPLAINABILITY_V1, SELECTIVE_TRANSFORMATION_V1), MAVEN_BUILD_SKIP_UNIT_TESTS) + val context = CodeModernizerSessionContext( + project, + root.children[0], + JavaSdkVersion.JDK_1_8, + JavaSdkVersion.JDK_11, + listOf(EXPLAINABILITY_V1, SELECTIVE_TRANSFORMATION_V1), + MAVEN_BUILD_SKIP_UNIT_TESTS + ) val mockFile = mock(File::class.java) val mockStringBuilder = mock(StringBuilder::class.java) val file = runInEdtAndGet { diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt index 09d0b70e0a1..6579cf2ad6f 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt @@ -130,8 +130,13 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { doReturn(result).whenever(handler).downloadArtifact(any(), eq(TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS), eq(false)) handler.displayDiff(jobId, CodeTransformVCSViewerSrcComponents.Chat) verify(handler, never()).notifyUnableToApplyPatch(any()) - verify(handler, times(1)).displayDiffUsingPatch(testCodeModernizerArtifact.patches[0], testCodeModernizerArtifact.patches.size, - testCodeModernizerArtifact.description?.get(0), jobId, CodeTransformVCSViewerSrcComponents.Chat) + verify(handler, times(1)).displayDiffUsingPatch( + testCodeModernizerArtifact.patches[0], + testCodeModernizerArtifact.patches.size, + testCodeModernizerArtifact.description?.get(0), + jobId, + CodeTransformVCSViewerSrcComponents.Chat + ) } @Test @@ -154,11 +159,18 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { @Test fun `CodeModernizerArtifact can process a valid zip file`() { val artifact = CodeModernizerArtifact.create(exampleZipPath.toAbsolutePath().toString()) - assertEquals(1, artifact.patches.size) assertEquals(validManifest, artifact.manifest) assertEquals(validMetrics.linesOfCodeChanged, artifact.metrics?.linesOfCodeChanged) } + @Test + fun `CodeModernizerArtifact can process a valid zip file with multiple diffs`() { + val artifact = CodeModernizerArtifact.create(multipleDiffZipPath.toAbsolutePath().toString()) + assertEquals(4, artifact.patches.size) + assertEquals(validManifest, artifact.manifest) + assertEquals(validMetricsMultipleDiffs.linesOfCodeChanged, artifact.metrics?.linesOfCodeChanged) + } + @Test fun `can unzip a file`() { val tempDir = createTempDirectory() @@ -168,6 +180,15 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { assert(tempDir.resolve(validZipPatchFilePath).exists()) } + @Test + fun `can unzip a file with multiple diffs`() { + val tempDir = createTempDirectory() + val result = unzipFile(multipleDiffZipPath, tempDir) + assert(result) + assert(tempDir.resolve(validZipManifestPath).exists()) + assert(tempDir.resolve(validZipPatchFilePath).exists()) + } + @Test fun `returns False when unable to unzip file`() { assertFalse(unzipFile(Path("dummy1"), Path("dummy2"))) diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt index 4667db7dec9..bf67924abcb 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt @@ -107,6 +107,7 @@ open class CodeWhispererCodeModernizerTestBase( internal lateinit var testCodeModernizerArtifact: CodeModernizerArtifact internal lateinit var testTransformFailureBuildLog: CodeTransformFailureBuildLog internal val exampleZipPath = "simple.zip".toResourceFile().toPath() + internal val multipleDiffZipPath = "multiple-diff.zip".toResourceFile().toPath() internal val expectedFilePath = "expectedFile".toResourceFile().toPath() internal val overwrittenFilePath = "overwrittenFile".toResourceFile().toPath() internal val testRequestId = "test_aws_request_id" @@ -150,6 +151,14 @@ open class CodeWhispererCodeModernizerTestBase( programmingLanguage = "JAVA", ) + internal val validMetricsMultipleDiffs = + CodeModernizerMetrics( + charactersOfCodeChanged = 83, + linesOfCodeChanged = 3, + linesOfCodeSubmitted = 567, + programmingLanguage = "JAVA", + ) + internal val exampleCreateUploadUrlResponse = CreateUploadUrlResponse.builder() .uploadUrl("https://smth.com") @@ -290,8 +299,14 @@ open class CodeWhispererCodeModernizerTestBase( val summaryFileMock = Mockito.mock(File::class.java) val logFileMock = Mockito.mock(File::class.java) doReturn("dummy/path").whenever(virtualFileMock).path - testSessionContextSpy = spy(CodeModernizerSessionContext(project, virtualFileMock, JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11, - listOf("EXPLAINABILITY_V1", "SELECTIVE_TRANSFORMATION_V1"), "test")) + testSessionContextSpy = spy(CodeModernizerSessionContext( + project, + virtualFileMock, + JavaSdkVersion.JDK_1_8, + JavaSdkVersion.JDK_11, + listOf("EXPLAINABILITY_V1", "SELECTIVE_TRANSFORMATION_V1"), + "test") + ) testSessionSpy = spy(CodeModernizerSession(testSessionContextSpy, 0, 0)) doNothing().whenever(testSessionSpy).deleteUploadArtifact(any()) From b07c148bfee765af497dfa075f10c4f4b825f32d Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Tue, 19 Nov 2024 15:15:37 -0800 Subject: [PATCH 16/19] addressing comments on PR, detekt issues, and adding feature flag --- .../codemodernizer/ArtifactHandler.kt | 100 +++++++++--------- .../controller/CodeTransformChatController.kt | 15 ++- .../model/CodeModernizerArtifact.kt | 9 +- .../CodeWhispererCodeModernizerTestBase.kt | 30 ++++-- .../resources/MessagesBundle.properties | 4 +- 5 files changed, 87 insertions(+), 71 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index bfa0fc67f2e..f1097a12179 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -15,11 +15,6 @@ import com.intellij.openapi.vcs.changes.patch.ApplyPatchMode import com.intellij.openapi.vcs.changes.patch.ImportToShelfExecutor import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile -import java.io.File -import java.nio.file.Files -import java.nio.file.Path -import java.time.Instant -import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType @@ -28,6 +23,7 @@ import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.exists import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.info +import software.aws.toolkits.jetbrains.core.coroutines.EDT import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.NoTokenInitializedException @@ -55,16 +51,22 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModerni import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction +import software.aws.toolkits.jetbrains.utils.notifyInfo import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformArtifactType import software.aws.toolkits.telemetry.CodeTransformVCSViewerSrcComponents +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.time.Instant +import java.util.concurrent.atomic.AtomicBoolean const val DOWNLOAD_PROXY_WILDCARD_ERROR: String = "Dangling meta character '*' near index 0" const val DOWNLOAD_SSL_HANDSHAKE_ERROR: String = "Unable to execute HTTP request: javax.net.ssl.SSLHandshakeException" const val INVALID_ARTIFACT_ERROR: String = "Invalid artifact" -val patchDescriptions: Map = mapOf( +val patchDescriptions = mapOf( "Prepare minimal upgrade to Java 17" to "This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.", "Popular Enterprise Specifications and Application Frameworks upgrade" to "This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, " + "and Micronaut 3.", @@ -74,8 +76,7 @@ val patchDescriptions: Map = mapOf( "Jenkins plugins and the Maven Wrapper.", "Miscellaneous Processing Documentation upgrade" to "This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, " + "and more.", - "Updated dependencies to latest version" to "", - "Upgrade Deprecated API" to "" + "Deprecated API replacement and dependency upgrades" to "This diff patch replaces deprecated APIs and makes additional dependency version upgrades." ) class ArtifactHandler( @@ -89,6 +90,7 @@ class ArtifactHandler( private val downloadedBuildLogPath = mutableMapOf() private var isCurrentlyDownloading = AtomicBoolean(false) private var totalPatchFiles: Int = 0 + private var sharedPatchIndex: Int = 0 internal suspend fun displayDiff(job: JobId, source: CodeTransformVCSViewerSrcComponents) { if (isCurrentlyDownloading.get()) return @@ -277,14 +279,14 @@ class ArtifactHandler( /** * Opens the built-in patch dialog to display the diff and allowing users to apply the changes locally. */ - internal fun displayDiffUsingPatch( + internal suspend fun displayDiffUsingPatch( patchFile: VirtualFile, totalPatchFiles: Int, diffDescription: PatchInfo?, jobId: JobId, source: CodeTransformVCSViewerSrcComponents, ) { - runInEdt { + withContext(EDT) { val dialog = ApplyPatchDifferentiatedDialog( project, ApplyPatchDefaultExecutor(project), @@ -309,44 +311,41 @@ class ArtifactHandler( dialog.isModal = true if (dialog.showAndGet()) { - projectCoroutineScope(project).launch { - telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) - if (diffDescription == null) { - val message = "I applied the changes to your project." - val resultContent = CodeTransformChatMessageContent( - type = CodeTransformChatMessageType.PendingAnswer, - message = message, - ) - codeTransformChatHelper?.updateLastPendingMessage(resultContent) - codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) - } else { - if (getCurrentPatchIndex() < totalPatchFiles) { - val message = "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. " + - "${patchDescriptions[diffDescription.name]}" - val notificationMessage = "Amazon Q applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles " + - "to your project." - val notificationTitle = "Diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles applied" - setCurrentPatchIndex(getCurrentPatchIndex() + 1) - notifyStickyInfo(notificationTitle, notificationMessage, project) - if (getCurrentPatchIndex() == totalPatchFiles) { - codeTransformChatHelper?.updateLastPendingMessage( - CodeTransformChatMessageContent(type = CodeTransformChatMessageType.PendingAnswer, message = message) - ) - } else { - codeTransformChatHelper?.updateLastPendingMessage( - CodeTransformChatMessageContent( - type = CodeTransformChatMessageType.PendingAnswer, - message = message, - buttons = listOf( - createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/$totalPatchFiles"), - viewSummaryButton - ) + telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) + if (diffDescription == null) { + val resultContent = CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message("codemodernizer.chat.message.changes_applied"), + ) + codeTransformChatHelper?.updateLastPendingMessage(resultContent) + codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) + } else { + if (getCurrentPatchIndex() < totalPatchFiles) { + val message = "I applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles. " + + "${patchDescriptions[diffDescription.name]}" + val notificationMessage = "Amazon Q applied the changes in diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles " + + "to your project." + val notificationTitle = "Diff patch ${getCurrentPatchIndex() + 1} of $totalPatchFiles applied" + setCurrentPatchIndex(getCurrentPatchIndex() + 1) + notifyInfo(notificationTitle, notificationMessage, project) + if (getCurrentPatchIndex() == totalPatchFiles) { + codeTransformChatHelper?.updateLastPendingMessage( + CodeTransformChatMessageContent(type = CodeTransformChatMessageType.PendingAnswer, message = message) + ) + } else { + codeTransformChatHelper?.updateLastPendingMessage( + CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.PendingAnswer, + message = message, + buttons = listOf( + createViewDiffButton("View diff ${getCurrentPatchIndex() + 1}/$totalPatchFiles"), + viewSummaryButton ) ) - } - } else { - codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) + ) } + } else { + codeTransformChatHelper?.addNewMessage(buildStartNewTransformFollowup()) } } } else { @@ -471,6 +470,12 @@ class ArtifactHandler( fun getSummary(job: JobId) = downloadedSummaries[job] + private fun getCurrentPatchIndex() = sharedPatchIndex + + private fun setCurrentPatchIndex(index: Int) { + sharedPatchIndex = index + } + private fun showSummaryFromFile(summaryFile: File) { val summaryMarkdownVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(summaryFile) if (summaryMarkdownVirtualFile != null) { @@ -529,10 +534,5 @@ class ArtifactHandler( companion object { val LOG = getLogger() - private var sharedPatchIndex: Int = 0 - fun getCurrentPatchIndex() = sharedPatchIndex - fun setCurrentPatchIndex(index: Int) { - sharedPatchIndex = index - } } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index d30897f99f8..6cf97e7a296 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -29,6 +29,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTele import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.HilTelemetryMetaData import software.aws.toolkits.jetbrains.services.codemodernizer.InboundAppMessagesHandler +import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFORMATION_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformActionMessage import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformCommand @@ -98,7 +99,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenDepend import software.aws.toolkits.jetbrains.services.codemodernizer.model.UploadFailureReason import software.aws.toolkits.jetbrains.services.codemodernizer.model.ValidationResult import software.aws.toolkits.jetbrains.services.codemodernizer.panels.managers.CodeModernizerBottomWindowPanelManager -import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFORMATION_V1 import software.aws.toolkits.jetbrains.services.codemodernizer.session.ChatSessionStorage import software.aws.toolkits.jetbrains.services.codemodernizer.session.Session import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState @@ -378,13 +378,20 @@ class CodeTransformChatController( message("codemodernizer.chat.message.skip_tests_form.skip") -> MAVEN_BUILD_SKIP_UNIT_TESTS else -> MAVEN_BUILD_RUN_UNIT_TESTS } + //feature flag for Selective Transformation + val isSelectiveTransformationReady = false codeTransformChatHelper.addNewMessage(buildUserSkipTestsFlagSelectionChatContent(message.skipTestsSelection)) codeModernizerManager.codeTransformationSession?.let { it.sessionContext.customBuildCommand = customBuildCommand + if (!isSelectiveTransformationReady){ + codeModernizerManager.runLocalMavenBuild(context.project, it) + } } - codeTransformChatHelper.run { - addNewMessage(buildUserInputOneOrMultipleDiffsChatIntroContent()) - addNewMessage(buildUserInputOneOrMultipleDiffsFlagChatContent()) + if (isSelectiveTransformationReady){ + codeTransformChatHelper.run { + addNewMessage(buildUserInputOneOrMultipleDiffsChatIntroContent()) + addNewMessage(buildUserInputOneOrMultipleDiffsFlagChatContent()) + } } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index f209e2b0ffc..d8b58547acd 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -117,7 +117,6 @@ open class CodeModernizerArtifact( } } - @OptIn(ExperimentalPathApi::class) private fun extractPatches(manifest: CodeModernizerManifest, description: List?): List { if (description == null) { return extractSinglePatch(manifest) @@ -125,15 +124,15 @@ open class CodeModernizerArtifact( val fileSystem = LocalFileSystem.getInstance() val patchesDir = tempDir.toPath().resolve(manifest.patchesRoot) if (!patchesDir.isDirectory()) { - throw RuntimeException("Expected root for patches was not a directory.") + error("Expected root for patches was not a directory.") } return description.map { patchInfo -> val patchFile = patchesDir.resolve(patchInfo.filename) if (patchFile.toFile().exists()) { fileSystem.findFileByNioFile(patchFile) - ?: throw RuntimeException("Could not find patch: ${patchInfo.filename}") + ?: error("Could not find patch: ${patchInfo.filename}") } else { - throw RuntimeException("Patch file not found: ${patchInfo.filename}") + error("Patch file not found: ${patchInfo.filename}") } } } @@ -163,7 +162,7 @@ open class CodeModernizerArtifact( // No JSON description file found, return null return null } - val descriptionContent: DescriptionContent = MAPPER.readValue(descriptionFile, DescriptionContent::class.java) + val descriptionContent: DescriptionContent = MAPPER.readValue(descriptionFile) return descriptionContent.content } } diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt index bf67924abcb..a02cd5baa97 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt @@ -93,8 +93,10 @@ open class CodeWhispererCodeModernizerTestBase( internal val minJDKUpgradePatchResource = "min_jdk_upgrade.patch".toResourceFile() internal val minJDKUpgradePatchResourceFile = LightVirtualFile("min_jdk_upgrade.patch", minJDKUpgradePatchResource.readText()) internal val enterpriseApplicationUpgradePatchResource = "popular_enterprise_application_framework.patch".toResourceFile() - internal val enterpriseApplicationUpgradePatchResourceFile = LightVirtualFile("popular_enterprise_application_framework.patch", - enterpriseApplicationUpgradePatchResource.readText()) + internal val enterpriseApplicationUpgradePatchResourceFile = LightVirtualFile( + "popular_enterprise_application_framework.patch", + enterpriseApplicationUpgradePatchResource.readText() + ) internal val testingToolPatchResource = "testing_tool.patch".toResourceFile() internal val testingToolPatchResourceFile = LightVirtualFile("testing_tool.patch", testingToolPatchResource.readText()) internal val deprecatedAPIPatchResource = "update_deprecated_api.patch".toResourceFile() @@ -299,13 +301,15 @@ open class CodeWhispererCodeModernizerTestBase( val summaryFileMock = Mockito.mock(File::class.java) val logFileMock = Mockito.mock(File::class.java) doReturn("dummy/path").whenever(virtualFileMock).path - testSessionContextSpy = spy(CodeModernizerSessionContext( - project, - virtualFileMock, - JavaSdkVersion.JDK_1_8, - JavaSdkVersion.JDK_11, - listOf("EXPLAINABILITY_V1", "SELECTIVE_TRANSFORMATION_V1"), - "test") + testSessionContextSpy = spy( + CodeModernizerSessionContext( + project, + virtualFileMock, + JavaSdkVersion.JDK_1_8, + JavaSdkVersion.JDK_11, + listOf("EXPLAINABILITY_V1", "SELECTIVE_TRANSFORMATION_V1"), + "test" + ) ) testSessionSpy = spy(CodeModernizerSession(testSessionContextSpy, 0, 0)) @@ -316,8 +320,12 @@ open class CodeWhispererCodeModernizerTestBase( CodeModernizerArtifact( exampleZipPath.toAbsolutePath().toString(), validManifest, - listOf(minJDKUpgradePatchResourceFile, enterpriseApplicationUpgradePatchResourceFile, - testingToolPatchResourceFile, deprecatedAPIPatchResourceFile), + listOf( + minJDKUpgradePatchResourceFile, + enterpriseApplicationUpgradePatchResourceFile, + testingToolPatchResourceFile, + deprecatedAPIPatchResourceFile + ), exampleDescriptionContent.content, validTransformationSummary, summaryFileMock, diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index 39a96a017e6..dd0625aa648 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -583,6 +583,7 @@ codemodernizer.chat.message.button.view_diff=View diff codemodernizer.chat.message.button.view_failure_build_log=View Failure Build Log codemodernizer.chat.message.button.view_summary=View summary codemodernizer.chat.message.choose_objective=Enter "language upgrade" or "SQL conversion" +codemodernizer.chat.message.changes_applied=I applied the changes to your project. codemodernizer.chat.message.download_failed_client_instructions_expired=Your transformation is not available anymore. Your code and transformation summary are deleted 24 hours after the transformation completes. Please try starting the transformation again. codemodernizer.chat.message.download_failed_invalid_artifact=Sorry, I was unable to find your {0}. Artifacts are deleted after 24 hours. Please try starting the transformation again. codemodernizer.chat.message.download_failed_other=Sorry, I ran into an issue while trying to download your {0}. Please try again. {1} @@ -617,7 +618,8 @@ I can now divide the transformation results into diff patches (if applicable to - Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ - HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ - Testing Tools Frameworks: Testing tools like ArchUnit, Mockito, and TestContainers and build tools like Jenkins and Maven Wrapper.\n\n\ -- Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI. +- Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI.\n\n\ +- Deprecated API replacement and dependency upgrades: Replaces deprecated APIs and makes additional dependency version upgrades. codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} when providing the proposed changes. From 14992ff17c8b234c41914f16a2985469a71dfcb3 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Tue, 19 Nov 2024 19:39:06 -0800 Subject: [PATCH 17/19] adding feature flag and telemetry --- .../jetbrains/services/codemodernizer/ArtifactHandler.kt | 1 + .../jetbrains/services/codemodernizer/client/GumbyClient.kt | 2 +- .../controller/CodeTransformChatController.kt | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index f1097a12179..4717860771c 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -311,6 +311,7 @@ class ArtifactHandler( dialog.isModal = true if (dialog.showAndGet()) { + telemetry.submitSelection("Submit-${patchDescriptions[diffDescription?.name]}") telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) if (diffDescription == null) { val resultContent = CodeTransformChatMessageContent( diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt index c4378c9077f..2a92dc33d04 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt @@ -222,7 +222,7 @@ class GumbyClient(private val project: Project) { it.timestamp(Instant.now()) it.ideCategory(IdeCategory.JETBRAINS) it.programmingLanguage { language -> - language.languageName(metrics.programmingLanguage) + language.languageName(metrics.programmingLanguage?.lowercase()) } it.linesOfCodeChanged(metrics.linesOfCodeChanged) it.charsOfCodeChanged(metrics.charactersOfCodeChanged) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt index 6cf97e7a296..5edbe1d465e 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt @@ -378,16 +378,16 @@ class CodeTransformChatController( message("codemodernizer.chat.message.skip_tests_form.skip") -> MAVEN_BUILD_SKIP_UNIT_TESTS else -> MAVEN_BUILD_RUN_UNIT_TESTS } - //feature flag for Selective Transformation + // feature flag for Selective Transformation val isSelectiveTransformationReady = false codeTransformChatHelper.addNewMessage(buildUserSkipTestsFlagSelectionChatContent(message.skipTestsSelection)) codeModernizerManager.codeTransformationSession?.let { it.sessionContext.customBuildCommand = customBuildCommand - if (!isSelectiveTransformationReady){ + if (!isSelectiveTransformationReady) { codeModernizerManager.runLocalMavenBuild(context.project, it) } } - if (isSelectiveTransformationReady){ + if (isSelectiveTransformationReady) { codeTransformChatHelper.run { addNewMessage(buildUserInputOneOrMultipleDiffsChatIntroContent()) addNewMessage(buildUserInputOneOrMultipleDiffsFlagChatContent()) From 6fb6f3f789d0ebdc07082f2c1ae66780c15cbf91 Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Tue, 19 Nov 2024 19:58:00 -0800 Subject: [PATCH 18/19] fixing telemetry and readValue --- .../jetbrains/services/codemodernizer/ArtifactHandler.kt | 2 +- .../services/codemodernizer/model/CodeModernizerArtifact.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt index 4717860771c..40ece3b768a 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt @@ -311,7 +311,7 @@ class ArtifactHandler( dialog.isModal = true if (dialog.showAndGet()) { - telemetry.submitSelection("Submit-${patchDescriptions[diffDescription?.name]}") + telemetry.submitSelection("Submit-${diffDescription?.name}") telemetry.viewArtifact(CodeTransformArtifactType.ClientInstructions, jobId, "Submit", source) if (diffDescription == null) { val resultContent = CodeTransformChatMessageContent( diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt index d8b58547acd..2896ba41127 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerArtifact.kt @@ -162,7 +162,7 @@ open class CodeModernizerArtifact( // No JSON description file found, return null return null } - val descriptionContent: DescriptionContent = MAPPER.readValue(descriptionFile) + val descriptionContent: DescriptionContent = MAPPER.readValue(descriptionFile) return descriptionContent.content } } From 98c9eab1830ce4da0451e6e69e70b4aec1f0e15e Mon Sep 17 00:00:00 2001 From: Neha Tarakad Date: Tue, 19 Nov 2024 21:11:29 -0800 Subject: [PATCH 19/19] fixing failed test and lint --- .../codemodernizer/CodeWhispererCodeModernizerTest.kt | 9 +++++++++ .../aws/toolkits/resources/MessagesBundle.properties | 11 ++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt index 6579cf2ad6f..e8de6cfc5c3 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt @@ -3,12 +3,15 @@ package software.aws.toolkits.jetbrains.services.codemodernizer +import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog import com.intellij.testFramework.LightVirtualFile import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertFalse import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Test +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.mock import org.mockito.kotlin.any import org.mockito.kotlin.doNothing import org.mockito.kotlin.doReturn @@ -128,6 +131,12 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { val path = testCodeModernizerArtifact.zipPath val result = DownloadArtifactResult.Success(testCodeModernizerArtifact, path) doReturn(result).whenever(handler).downloadArtifact(any(), eq(TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS), eq(false)) + val mockDialog = mock() + whenever(mockDialog.showAndGet()).thenReturn(true) + doAnswer { + mockDialog.showAndGet() + mockDialog + }.whenever(handler).displayDiffUsingPatch(any(), any(), any(), any(), any()) handler.displayDiff(jobId, CodeTransformVCSViewerSrcComponents.Chat) verify(handler, never()).notifyUnableToApplyPatch(any()) verify(handler, times(1)).displayDiffUsingPatch( diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index dd0625aa648..543c7c8b69e 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -582,8 +582,8 @@ codemodernizer.chat.message.button.view_build=View build progress codemodernizer.chat.message.button.view_diff=View diff codemodernizer.chat.message.button.view_failure_build_log=View Failure Build Log codemodernizer.chat.message.button.view_summary=View summary -codemodernizer.chat.message.choose_objective=Enter "language upgrade" or "SQL conversion" codemodernizer.chat.message.changes_applied=I applied the changes to your project. +codemodernizer.chat.message.choose_objective=Enter "language upgrade" or "SQL conversion" codemodernizer.chat.message.download_failed_client_instructions_expired=Your transformation is not available anymore. Your code and transformation summary are deleted 24 hours after the transformation completes. Please try starting the transformation again. codemodernizer.chat.message.download_failed_invalid_artifact=Sorry, I was unable to find your {0}. Artifacts are deleted after 24 hours. Please try starting the transformation again. codemodernizer.chat.message.download_failed_other=Sorry, I ran into an issue while trying to download your {0}. Please try again. {1} @@ -612,14 +612,7 @@ codemodernizer.chat.message.hil.user_rejected=I'll continue upgrading your modul codemodernizer.chat.message.local_build_begin=I'm building your module. This can take up to 10 minutes, depending on the size of your module. codemodernizer.chat.message.local_build_failed=Sorry, I couldn't run the Maven clean install command to build your module. codemodernizer.chat.message.local_build_success=I was able to build your module and will start uploading your code. -codemodernizer.chat.message.one_or_multiple_diffs=\ -I can now divide the transformation results into diff patches (if applicable to the app) if you would like to review and accept each diff with fewer changes:\n\n\ -- Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito.\n\n\ -- Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ -- HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ -- Testing Tools Frameworks: Testing tools like ArchUnit, Mockito, and TestContainers and build tools like Jenkins and Maven Wrapper.\n\n\ -- Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI.\n\n\ -- Deprecated API replacement and dependency upgrades: Replaces deprecated APIs and makes additional dependency version upgrades. +codemodernizer.chat.message.one_or_multiple_diffs=I can now divide the transformation results into diff patches (if applicable to the app) if you would like to review and accept each diff with fewer changes:\n\n\ - Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito.\n\n\ - Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3.\n\n\ - HTTP Client Utilities Web Frameworks: HTTP client libraries, Apache Commons utilities, and Struts frameworks.\n\n\ - Testing Tools Frameworks: Testing tools like ArchUnit, Mockito, and TestContainers and build tools like Jenkins and Maven Wrapper.\n\n\ - Miscellaneous Processing Documentation: Diverse set spanning ORMs, XML processing, and API documentation like Swagger to SpringDoc/OpenAPI.\n\n\ - Deprecated API replacement and dependency upgrades: Replaces deprecated APIs and makes additional dependency version upgrades. codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} when providing the proposed changes.