From f086e09bd9924a01c57dd36ef7872fc44626cccc Mon Sep 17 00:00:00 2001 From: David Hasani Date: Mon, 24 Mar 2025 12:43:58 -0700 Subject: [PATCH 01/16] first commit for csb --- .../codemodernizer/CodeTransformChatApp.kt | 8 ++- .../InboundAppMessagesHandler.kt | 4 ++ .../constants/CodeTransformChatItems.kt | 39 +++++++++++ .../controller/CodeTransformChatController.kt | 70 ++++++++++++++++++- .../ideMaven/MavenRunnerUtils.kt | 7 ++ .../messages/CodeTransformMessage.kt | 10 +++ .../model/CodeModernizerSessionContext.kt | 1 + .../codemodernizer/model/CustomerSelection.kt | 3 +- .../utils/CodeTransformFileUtils.kt | 12 ++++ .../CodeWhispererCodeModernizerUtilsTest.kt | 41 +++++++++++ .../ui/apps/codeTransformChatConnector.ts | 14 +++- .../mynah-ui/src/mynah-ui/ui/commands.ts | 2 + .../src/mynah-ui/ui/forms/constants.ts | 4 ++ 13 files changed, 210 insertions(+), 5 deletions(-) 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 b102d348d11..584a3424607 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 @@ -41,9 +41,11 @@ private enum class CodeTransformMessageTypes(val type: String) { ChatPrompt("chat-prompt"), // for getting the transformation objective CodeTransformStart("codetransform-start"), CodeTransformSelectSQLMetadata("codetransform-select-sql-metadata"), + CodeTransformConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"), CodeTransformSelectSQLModuleSchema("codetransform-select-sql-module-schema"), CodeTransformStop("codetransform-stop"), CodeTransformCancel("codetransform-cancel"), + CodeTransformContinue("codetransform-continue"), CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"), CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"), CodeTransformNew("codetransform-new"), @@ -74,9 +76,11 @@ class CodeTransformChatApp : AmazonQApp { CodeTransformMessageTypes.Transform.type to IncomingCodeTransformMessage.Transform::class, CodeTransformMessageTypes.CodeTransformStart.type to IncomingCodeTransformMessage.CodeTransformStart::class, CodeTransformMessageTypes.CodeTransformSelectSQLMetadata.type to IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata::class, + CodeTransformMessageTypes.CodeTransformConfirmCustomDependencyVersions.type to IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions::class, CodeTransformMessageTypes.CodeTransformSelectSQLModuleSchema.type to IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema::class, CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class, CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class, + CodeTransformMessageTypes.CodeTransformContinue.type to IncomingCodeTransformMessage.CodeTransformContinue::class, CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class, CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class, CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class, @@ -182,12 +186,14 @@ class CodeTransformChatApp : AmazonQApp { is IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata -> inboundAppMessagesHandler.processCodeTransformSelectSQLMetadataAction(message) is IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema -> inboundAppMessagesHandler.processCodeTransformSelectSQLModuleSchemaAction(message) - + is IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions -> + inboundAppMessagesHandler.processCodeTransformCustomDependencyVersions(message) is IncomingCodeTransformMessage.CodeTransformCancel -> inboundAppMessagesHandler.processCodeTransformCancelAction(message) is IncomingCodeTransformMessage.CodeTransformStop -> inboundAppMessagesHandler.processCodeTransformStopAction(message.tabId) is IncomingCodeTransformMessage.ChatPrompt -> inboundAppMessagesHandler.processChatPromptMessage(message) is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message) is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message) + is IncomingCodeTransformMessage.CodeTransformContinue -> inboundAppMessagesHandler.processCodeTransformContinueAction(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 1312328243e..434516178bd 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 @@ -11,12 +11,16 @@ interface InboundAppMessagesHandler { suspend fun processCodeTransformCancelAction(message: IncomingCodeTransformMessage.CodeTransformCancel) + suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) + suspend fun processCodeTransformStartAction(message: IncomingCodeTransformMessage.CodeTransformStart) suspend fun processCodeTransformSelectSQLMetadataAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata) suspend fun processCodeTransformSelectSQLModuleSchemaAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema) + suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) + suspend fun processCodeTransformStopAction(tabId: String) suspend fun processChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) 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 c39d530e6b2..a68e81cef23 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 @@ -44,6 +44,14 @@ private val cancelUserSelectionButton = Button( id = CodeTransformButtonId.CancelTransformation.id, ) +// used to continue transformation without providing custom YAML file +private val continueTransformationButton = Button( + keepCardAfterClick = false, + waitMandatoryFormItems = false, + text = "Continue without this", + id = CodeTransformButtonId.ContinueTransformation.id, +) + private val confirmUserSelectionLanguageUpgradeButton = Button( keepCardAfterClick = false, waitMandatoryFormItems = true, @@ -79,6 +87,13 @@ private val confirmOneOrMultipleDiffsSelectionButton = Button( id = CodeTransformButtonId.ConfirmOneOrMultipleDiffs.id, ) +private val confirmCustomDependencyVersionsButton = Button( + keepCardAfterClick = true, + waitMandatoryFormItems = true, // TODO: what does this do? + text = "Select file", + id = CodeTransformButtonId.ConfirmCustomDependencyVersions.id, +) + private val openMvnBuildButton = Button( id = CodeTransformButtonId.OpenMvnBuild.id, text = message("codemodernizer.chat.message.button.view_build"), @@ -375,6 +390,20 @@ fun buildUserInputSQLConversionMetadataChatContent() = CodeTransformChatMessageC type = CodeTransformChatMessageType.FinalizedAnswer, ) +fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessageContent( + message = "Optionally, provide a .YAML file which specifies custom dependency versions you want Q to upgrade to.", + buttons = listOf( + confirmCustomDependencyVersionsButton, + continueTransformationButton, + ), + type = CodeTransformChatMessageType.FinalizedAnswer, +) + +fun buildCustomDependencyVersionsFileValidChatContent() = CodeTransformChatMessageContent( + message = "I received your .yaml file and will upload it to Q.", + type = CodeTransformChatMessageType.FinalizedAnswer, +) + fun buildModuleSchemaFormChatContent(project: Project, javaModules: List, schemaOptions: Set) = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.FinalizedAnswer, buttons = listOf( @@ -416,6 +445,11 @@ fun buildSQLMetadataValidationErrorChatContent(errorReason: String) = CodeTransf message = errorReason, ) +fun buildCustomDependencyVersionsFileInvalidChatContent() = CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.FinalizedAnswer, + message = "The .yaml file you uploaded does not follow the format of the sample YAML file provided.", +) + fun buildUserCancelledChatContent() = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.FinalizedAnswer, message = message("codemodernizer.chat.message.transform_cancelled_by_user"), @@ -451,6 +485,11 @@ fun buildUserLanguageUpgradeSelectionSummaryChatContent(moduleName: String, targ message = getUserLanguageUpgradeSelectionFormattedMarkdown(moduleName, targetJdkVersion) ) +fun buildContinueTransformationChatContent() = CodeTransformChatMessageContent( + type = CodeTransformChatMessageType.FinalizedAnswer, + message = "Ok, I will continue without this information.", +) + fun buildCompileLocalInProgressChatContent() = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.PendingAnswer, message = message("codemodernizer.chat.message.local_build_begin"), 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 b292aaf6aaa..322f745a8fb 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 @@ -11,6 +11,7 @@ import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.readText import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -43,6 +44,9 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCo import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCompileLocalFailedNoJdkChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCompileLocalInProgressChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCompileLocalSuccessChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildContinueTransformationChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCustomDependencyVersionsFileInvalidChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCustomDependencyVersionsFileValidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildDownloadFailureChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilCannotResumeContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilErrorContent @@ -71,6 +75,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent 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.buildUserInputCustomDependencyVersionsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent @@ -112,9 +117,14 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.toVirtualFi import software.aws.toolkits.jetbrains.services.codemodernizer.utils.tryGetJdk import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.testFramework.LightVirtualFile +import org.jetbrains.yaml.YAMLFileType import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformPreValidationError @@ -353,7 +363,7 @@ class CodeTransformChatController( withContext(EDT) { val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() .withDescription("Select metadata file") - .withFileFilter { it.extension == "zip" } + .withExtensionFilter("zip") val selectedZipFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext val extractedZip = createTempDirectory("codeTransformSQLMetadata", null) @@ -422,9 +432,65 @@ class CodeTransformChatController( } telemetry.submitSelection(message.oneOrMultipleDiffsSelection) codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection)) - codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) + codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent()) + val sampleYAML = """ +name: "custom-dependency-management" +description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21" + +dependencyManagement: + dependencies: + - identifier: "com.example:library1" + targetVersion: "2.1.0" + versionProperty: "library1.version" # Optional + originType: "FIRST_PARTY" # or "THIRD_PARTY" # Optional + - identifier: "com.example:library2" + targetVersion: "3.0.0" + originType: "THIRD_PARTY" + plugins: + - identifier: "com.example.plugin" + targetVersion: "1.2.0" + versionProperty: "plugin.version" # Optional +""".trimIndent() + + val virtualFile = LightVirtualFile("sample-dependency-management.yaml", YAMLFileType.YML, sampleYAML) + virtualFile.isWritable = true + ApplicationManager.getApplication().invokeLater { + FileEditorManager.getInstance(context.project).openFile(virtualFile, true) + } codeModernizerManager.codeTransformationSession?.let { it.sessionContext.transformCapabilities = transformCapabilities + } + } + + override suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) { + withContext(EDT) { + val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() + .withDescription("Select .yaml file") + .withExtensionFilter("yaml") + val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext + val isValid = validateYamlFile(selectedFile.readText()) + if (!isValid) { + codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent()) + codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) + return@withContext + } + codeModernizerManager.codeTransformationSession?.let { + it.sessionContext.customDependencyVersionsFile = selectedFile + } + codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent()) + codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) + codeModernizerManager.codeTransformationSession?.let { + codeModernizerManager.runLocalMavenBuild(context.project, it) + } + } + } + + override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) { + codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent()) + // if user doesn't provide a custom .yaml file, just move on with local build + // TODO: potentially we want to ask user to provide target JDK path? + codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) + codeModernizerManager.codeTransformationSession?.let { 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 6629b8c2d34..e8c58ac552e 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 @@ -6,6 +6,7 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven import com.intellij.openapi.application.runInEdt import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.vfs.LocalFileSystem @@ -19,6 +20,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTele import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerSessionContext import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenCopyCommandsResult import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenDependencyReportCommandsResult +import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.telemetry.CodeTransformBuildCommand import software.aws.toolkits.telemetry.Result import java.io.File @@ -80,6 +82,11 @@ fun runMavenCopyCommands( val transformMvnRunner = TransformMavenRunner(project) context.mavenRunnerQueue.add(transformMvnRunner) val mvnSettings = MavenRunner.getInstance(project).settings.clone() // clone required to avoid editing user settings + notifyStickyInfo("current jreName", mvnSettings.jreName) + mvnSettings.setJreName("corretto-21") + // use ProjectJdkTable.getInstance().allJdks to join all of the "name"s of the list + val jreNames = ProjectJdkTable.getInstance().allJdks.joinToString(", ") { it.name } + notifyStickyInfo("jreNames", jreNames) val sourceVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(sourceFolder) val module = sourceVirtualFile?.let { ModuleUtilCore.findModuleForFile(it, project) } 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 9a32e82aff5..b26fcbaeae2 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 @@ -20,8 +20,10 @@ enum class CodeTransformButtonId(val id: String) { SelectSQLMetadata("codetransform-input-select-sql-metadata"), SelectSQLModuleSchema("codetransform-input-select-sql-module-schema"), CancelTransformation("codetransform-input-cancel"), + ContinueTransformation("codetransform-input-continue"), ConfirmSkipTests("codetransform-input-confirm-skip-tests"), ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"), + ConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"), StopTransformation("stop_transform"), OpenTransformationHub("open_transformation_hub"), OpenMvnBuild("open_mvn_build"), @@ -103,6 +105,10 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage { @JsonProperty("tabID") val tabId: String, ) : IncomingCodeTransformMessage + data class CodeTransformContinue( + @JsonProperty("tabID") val tabId: String, + ) : IncomingCodeTransformMessage + data class CodeTransformConfirmSkipTests( @JsonProperty("tabID") val tabId: String, val skipTestsSelection: String, @@ -113,6 +119,10 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage { val oneOrMultipleDiffsSelection: String, ) : IncomingCodeTransformMessage + data class CodeTransformConfirmCustomDependencyVersions( + @JsonProperty("tabID") val tabId: 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/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt index a0da0824a76..aed2867328d 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 @@ -74,6 +74,7 @@ data class CodeModernizerSessionContext( val sourceServerName: String? = null, var schema: String? = null, val sqlMetadataZip: File? = null, + var customDependencyVersionsFile: VirtualFile? = null, ) : Disposable { private val mapper = jacksonObjectMapper() private val ignoredDependencyFileExtensions = setOf(INVALID_SUFFIX_SHA, INVALID_SUFFIX_REPOSITORIES) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt index 151187c165a..d5e1ea24962 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt @@ -15,5 +15,6 @@ data class CustomerSelection( val targetVendor: String? = null, val sourceServerName: String? = null, val sqlMetadataZip: File? = null, - // note: schema and customBuildCommand are passed in to CodeModernizerSessionContext separately, *after* CodeModernizerSession is created + // note: schema / customBuildCommand / customDependencyVersionsFile are passed in to CodeModernizerSessionContext separately, + // *after* CodeModernizerSession is created ) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt index bba84915c2b..585bbb11877 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.application.runReadAction import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.readText import software.aws.toolkits.core.utils.createParentDirectories import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.exists @@ -142,6 +143,17 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo return report } +fun validateYamlFile(fileContents: String): Boolean { + val requiredKeys = listOf("dependencyManagement:", "identifier:", "targetVersion:") + for (key in requiredKeys) { + if (!fileContents.contains(key)) { + getLogger().error { "Missing yaml key: $key" } + return false + } + } + return true +} + fun validateSctMetadata(sctFile: File?): SqlMetadataValidationResult { if (sctFile == null) { return SqlMetadataValidationResult(false, message("codemodernizer.chat.message.validation.error.missing_sct_file")) diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index 948024cc99d..74416f5d4f5 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -28,6 +28,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransfo import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata import software.aws.toolkits.jetbrains.utils.notifyStickyWarn +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile import software.aws.toolkits.jetbrains.utils.rules.addFileToModule import software.aws.toolkits.resources.message import java.util.concurrent.atomic.AtomicBoolean @@ -240,6 +241,46 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase assertThat(expected).isEqualTo(actual) } + @Test + fun `WHEN validateYamlFile on fully valid yaml file THEN passes validation`() { + val sampleFileContents = """name: "custom-dependency-management" +description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21" +dependencyManagement: + dependencies: + - identifier: "com.example:library1" + targetVersion: "2.1.0" + versionProperty: "library1.version" + originType: "FIRST_PARTY" + plugins: + - identifier: "com.example.plugin" + targetVersion: "1.2.0" + versionProperty: "plugin.version" + """.trimIndent() + + val isValidYaml = validateYamlFile(sampleFileContents) + assertThat(isValidYaml).isTrue() + } + + @Test + fun `WHEN validateYamlFile on invalid yaml file THEN fails validation`() { + val sampleFileContents = """name: "custom-dependency-management" +description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21" +invalidKey: + dependencies: + - identifier: "com.example:library1" + targetVersion: "2.1.0" + versionProperty: "library1.version" + originType: "FIRST_PARTY" + plugins: + - identifier: "com.example.plugin" + targetVersion: "1.2.0" + versionProperty: "plugin.version" + """.trimIndent() + + val isValidYaml = validateYamlFile(sampleFileContents) + assertThat(isValidYaml).isFalse() + } + @Test fun `WHEN validateMetadataFile on fully valid sct file THEN passes validation`() { val sampleFileContents = """ 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 86ac9a3fe6f..00f759af458 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 @@ -280,7 +280,13 @@ export class CodeTransformChatConnector { tabID, tabType: 'codetransform', }) - } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) { + } else if (action.id === FormButtonIds.CodeTransformInputContinue) { + this.sendMessageToExtension({ + command: 'codetransform-continue', + tabID, + tabType: 'codetransform', + }) + } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) { this.sendMessageToExtension({ command: 'codetransform-confirm-skip-tests', tabID, @@ -294,6 +300,12 @@ export class CodeTransformChatConnector { tabType: 'codetransform', oneOrMultipleDiffsSelection: action.formItemValues?.oneOrMultipleDiffsSelection }) + } else if (action.id === FormButtonIds.CodeTransformInputCustomDependencyVersions) { + this.sendMessageToExtension({ + command: 'codetransform-input-confirm-custom-dependency-versions', + tabID, + tabType: 'codetransform', + }) } 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 5df19981b3f..01486f01f2a 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts @@ -36,8 +36,10 @@ type MessageCommand = | 'codetransform-select-sql-module-schema' | 'codetransform-cancel' | 'codetransform-stop' + | 'codetransform-continue' | 'codetransform-confirm-skip-tests' | 'codetransform-confirm-one-or-multiple-diffs' + | 'codetransform-input-confirm-custom-dependency-versions' | '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 e400e2a5541..22b913acf96 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 @@ -8,8 +8,10 @@ export const enum FormButtonIds { CodeTransformInputSQLMetadata = 'codetransform-input-select-sql-metadata', CodeTransformInputSQLModuleSchema = 'codetransform-input-select-sql-module-schema', CodeTransformInputCancel = 'codetransform-input-cancel', + CodeTransformInputContinue = 'codetransform-input-continue', CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests', CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs', + CodeTransformInputCustomDependencyVersions = 'codetransform-input-confirm-custom-dependency-versions', OpenMvnBuild = 'open_mvn_build', StopTransform = 'stop_transform', OpenTransformationHub = 'open_transformation_hub', @@ -46,7 +48,9 @@ export const isFormButtonCodeTransform = (id: string): boolean => { id === FormButtonIds.CodeTransformInputSQLMetadata || id === FormButtonIds.CodeTransformInputSQLModuleSchema || id === FormButtonIds.CodeTransformInputSkipTests || + id === FormButtonIds.CodeTransformInputContinue || id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs || + id === FormButtonIds.CodeTransformInputCustomDependencyVersions || id === FormButtonIds.CodeTransformViewDiff || id === FormButtonIds.CodeTransformViewSummary || id === FormButtonIds.CodeTransformViewBuildLog || From 4a66e31c7eca3e753a0e701bdd4ce7aee647dd8e Mon Sep 17 00:00:00 2001 From: David Hasani Date: Wed, 16 Apr 2025 11:18:19 -0700 Subject: [PATCH 02/16] rest of CSB --- .../META-INF/codetransform-ext-java.xml | 2 +- .../codemodernizer/ArtifactHandler.kt | 26 +--- .../codemodernizer/CodeModernizerManager.kt | 2 +- .../codemodernizer/CodeModernizerSession.kt | 23 ++-- .../codemodernizer/CodeTransformChatApp.kt | 3 + .../InboundAppMessagesHandler.kt | 2 + .../codemodernizer/client/GumbyClient.kt | 11 +- .../constants/CodeTransformChatItems.kt | 26 +++- .../controller/CodeTransformChatController.kt | 101 +++++++++----- .../ideMaven/MavenRunnerUtils.kt | 69 ++++++++-- .../ideMaven/TransformMavenRunner.kt | 28 ++-- .../ideMaven/TransformRunnable.kt | 2 +- .../messages/CodeTransformMessage.kt | 5 + .../BuildProgressTimelineStepDetailsList.kt | 2 +- .../model/CodeModernizerSessionContext.kt | 18 ++- .../model/CodeTransformConversationState.kt | 10 ++ .../codemodernizer/model/ZipManifest.kt | 3 +- .../panels/BuildProgressStepDetailsPanel.kt | 2 +- .../codemodernizer/session/Session.kt | 3 + .../utils/CodeTransformApiUtils.kt | 129 ++++++++++++++++++ .../utils/CodeTransformFileUtils.kt | 56 +++++++- .../utils/CodeTransformUtils.kt | 21 +++ .../CodeWhispererCodeModernizerTest.kt | 44 +++++- .../CodeWhispererCodeModernizerTestBase.kt | 1 - .../CodeWhispererCodeModernizerUtilsTest.kt | 100 ++++++++++++++ .../ui/apps/codeTransformChatConnector.ts | 8 +- .../mynah-ui/src/mynah-ui/ui/commands.ts | 1 + .../src/mynah-ui/ui/forms/constants.ts | 2 + .../resources/MessagesBundle.properties | 3 +- 29 files changed, 589 insertions(+), 114 deletions(-) create mode 100644 plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt diff --git a/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml b/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml index 614c5e18b10..9a4bb0e5d25 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml +++ b/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml @@ -18,7 +18,7 @@ + icon="AllIcons.Actions.Properties"/> 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 93d3da48e7e..6623f19ffa9 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 @@ -50,13 +50,13 @@ 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.services.codemodernizer.utils.zipToPath 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 java.io.File -import java.nio.file.Files import java.nio.file.Path import java.time.Instant import java.util.concurrent.atomic.AtomicBoolean @@ -112,32 +112,12 @@ class ArtifactHandler( } } - suspend fun unzipToPath(byteArrayList: List, outputDirPath: Path? = null): Pair { - val zipFilePath = withContext(getCoroutineBgContext()) { - if (outputDirPath == null) { - Files.createTempFile(null, ".zip") - } else { - Files.createTempFile(outputDirPath, null, ".zip") - } - } - var totalDownloadBytes = 0 - withContext(getCoroutineBgContext()) { - Files.newOutputStream(zipFilePath).use { - for (bytes in byteArrayList) { - it.write(bytes) - totalDownloadBytes += bytes.size - } - } - } - return zipFilePath to totalDownloadBytes - } - suspend fun downloadHilArtifact(jobId: JobId, artifactId: String, tmpDir: File): CodeTransformHilDownloadArtifact? { val downloadResultsResponse = clientAdaptor.downloadExportResultArchive(jobId, artifactId) return try { val tmpPath = tmpDir.toPath() - val (downloadZipFilePath, _) = unzipToPath(downloadResultsResponse, tmpPath) + val (downloadZipFilePath, _) = zipToPath(downloadResultsResponse, tmpPath) LOG.info { "Successfully converted the hil artifact download to a zip at ${downloadZipFilePath.toAbsolutePath()}." } CodeTransformHilDownloadArtifact.create(downloadZipFilePath, getPathToHilArtifactDir(tmpPath)) } catch (e: Exception) { @@ -211,7 +191,7 @@ class ArtifactHandler( val totalDownloadBytes: Int val zipPath: String try { - val result = unzipToPath(downloadResultsResponse) + val result = zipToPath(downloadResultsResponse) path = result.first totalDownloadBytes = result.second zipPath = path.toAbsolutePath().toString() 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 9b2db462a41..77b95e0e255 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 @@ -909,7 +909,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo // Add delay between upload complete and trying to resume delay(500) - codeTransformationSession?.resumeTransformFromHil() + codeTransformationSession?.resumeTransformation() } else { throw CodeModernizerException("Cannot create dependency zip for HIL") } 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 921a9ac0f2c..828b36d7db8 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 @@ -20,6 +20,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdateStatus import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUserActionStatus +import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.amazon.awssdk.services.ssooidc.model.SsoOidcException import software.aws.toolkits.core.utils.Waiters.waitUntil @@ -174,6 +175,7 @@ class CodeModernizerSession( } // for language upgrades, copyResult should always be Successful here, failure cases already handled val result = sessionContext.createZipWithModuleFiles(copyResult) + sessionContext.originalUploadZipPath = result.payload.toPath() if (result is ZipCreationResult.Missing1P) { telemetryErrorMessage = "Missing 1p dependencies" @@ -283,9 +285,7 @@ class CodeModernizerSession( return CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER(e.localizedMessage)) } finally { telemetry.uploadProject(payloadSize, startTime, true, telemetryErrorMessage) - if (payload != null) { - deleteUploadArtifact(payload) - } + // do not delete upload ZIP; re-used for client-side build } // Send upload completion message to chat (only if successful) @@ -309,12 +309,6 @@ class CodeModernizerSession( } } - internal fun deleteUploadArtifact(payload: File) { - if (!payload.delete()) { - LOG.warn { "Unable to delete upload artifact." } - } - } - private fun startJob(uploadId: String): StartTransformationResponse { val sourceLanguage = sessionContext.sourceJavaVersion.name.toTransformationLanguage() val targetLanguage = sessionContext.targetJavaVersion.name.toTransformationLanguage() @@ -341,9 +335,10 @@ class CodeModernizerSession( */ fun resumeJob(startTime: Instant, jobId: JobId) = state.putJobHistory(sessionContext, TransformationStatus.STARTED, jobId.id, startTime) - fun resumeTransformFromHil() { + fun resumeTransformation() { val clientAdaptor = GumbyClient.getInstance(sessionContext.project) clientAdaptor.resumeCodeTransformation(state.currentJobId as JobId, TransformationUserActionStatus.COMPLETED) + getLogger().info("Successfully resumed transformation with status of COMPLETED") } fun rejectHilAndContinue(): ResumeTransformationResponse { @@ -390,7 +385,7 @@ class CodeModernizerSession( /** * Adapted from [CodeWhispererCodeScanSession] */ - suspend fun uploadPayload(payload: File): String { + suspend fun uploadPayload(payload: File, uploadContext: UploadContext? = null): String { val sha256checksum: String = Base64.getEncoder().encodeToString( withContext(getCoroutineBgContext()) { DigestUtils.sha256(FileInputStream(payload)) @@ -400,7 +395,7 @@ class CodeModernizerSession( throw AlreadyDisposedException("Disposed when about to create upload URL") } val clientAdaptor = GumbyClient.getInstance(sessionContext.project) - val createUploadUrlResponse = clientAdaptor.createGumbyUploadUrl(sha256checksum) + val createUploadUrlResponse = clientAdaptor.createGumbyUploadUrl(sha256checksum, uploadContext) LOG.info { "Uploading project artifact at ${payload.path} with checksum $sha256checksum using uploadId: ${ @@ -428,9 +423,9 @@ class CodeModernizerSession( createUploadUrlResponse.kmsKeyArn().orEmpty(), ) { shouldStop.get() } } - LOG.info { "Upload to S3 succeeded" } + LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of ${uploadContext.toString()}" } if (!shouldStop.get()) { - LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())}ms" } + LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())} ms" } } return createUploadUrlResponse.uploadId() } 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 584a3424607..c7c51457d50 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 @@ -46,6 +46,7 @@ private enum class CodeTransformMessageTypes(val type: String) { CodeTransformStop("codetransform-stop"), CodeTransformCancel("codetransform-cancel"), CodeTransformContinue("codetransform-continue"), + CodeTransformAgree("codetransform-agree"), CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"), CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"), CodeTransformNew("codetransform-new"), @@ -81,6 +82,7 @@ class CodeTransformChatApp : AmazonQApp { CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class, CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class, CodeTransformMessageTypes.CodeTransformContinue.type to IncomingCodeTransformMessage.CodeTransformContinue::class, + CodeTransformMessageTypes.CodeTransformAgree.type to IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild::class, CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class, CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class, CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class, @@ -194,6 +196,7 @@ class CodeTransformChatApp : AmazonQApp { is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message) is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message) is IncomingCodeTransformMessage.CodeTransformContinue -> inboundAppMessagesHandler.processCodeTransformContinueAction(message) + is IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild -> inboundAppMessagesHandler.processCodeTransformAgreeToLocalBuild(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 434516178bd..208a8ad67d3 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 @@ -13,6 +13,8 @@ interface InboundAppMessagesHandler { suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) + suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild) + suspend fun processCodeTransformStartAction(message: IncomingCodeTransformMessage.CodeTransformStart) suspend fun processCodeTransformSelectSQLMetadataAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata) 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 6134e69ca22..f94e25d166f 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 @@ -61,12 +61,13 @@ class GumbyClient(private val project: Project) { private val amazonQStreamingClient get() = AmazonQStreamingClient.getInstance(project) - fun createGumbyUploadUrl(sha256Checksum: String): CreateUploadUrlResponse { + fun createGumbyUploadUrl(sha256Checksum: String, context: UploadContext? = null): CreateUploadUrlResponse { val request = CreateUploadUrlRequest.builder() .contentChecksumType(ContentChecksumType.SHA_256) .contentChecksum(sha256Checksum) .uploadIntent(UploadIntent.TRANSFORMATION) .profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn) + .uploadContext(context) .build() return callApi({ bearerClient().createUploadUrl(request) }, apiName = "CreateUploadUrl") } @@ -164,12 +165,12 @@ class GumbyClient(private val project: Project) { suspend fun downloadExportResultArchive( jobId: JobId, - hilDownloadArtifactId: String? = null, + downloadArtifactId: String? = null, downloadArtifactType: TransformationDownloadArtifactType? = TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS, ): MutableList = amazonQStreamingClient.exportResultArchive( jobId.id, ExportIntent.TRANSFORMATION, - if (hilDownloadArtifactId == null) { + if (downloadArtifactId == null) { null } else { ExportContext @@ -177,14 +178,14 @@ class GumbyClient(private val project: Project) { .transformationExportContext( TransformationExportContext .builder() - .downloadArtifactId(hilDownloadArtifactId) + .downloadArtifactId(downloadArtifactId) .downloadArtifactType(downloadArtifactType.toString()) .build() ) .build() }, { e -> - LOG.error(e) { "ExportResultArchive failed: ${e.message}" } + LOG.error(e) { "ExportResultArchive on job ${jobId.id} and artifact $downloadArtifactId failed: ${e.message}" } }, { startTime -> LOG.info { "ExportResultArchive latency: ${calculateTotalLatency(startTime, Instant.now())}" } 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 a68e81cef23..b408bcff53a 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 @@ -52,6 +52,14 @@ private val continueTransformationButton = Button( id = CodeTransformButtonId.ContinueTransformation.id, ) +// used to agree to local build +private val agreeToLocalBuildButton = Button( + keepCardAfterClick = false, + waitMandatoryFormItems = false, + text = "Agree", + id = CodeTransformButtonId.AgreeToLocalBuild.id, +) + private val confirmUserSelectionLanguageUpgradeButton = Button( keepCardAfterClick = false, waitMandatoryFormItems = true, @@ -282,11 +290,20 @@ fun buildChooseTransformationObjectiveChatContent() = CodeTransformChatMessageCo type = CodeTransformChatMessageType.FinalizedAnswer, ) -fun buildObjectiveChosenChatContent(objective: String) = CodeTransformChatMessageContent( - message = objective, +fun buildUserReplyChatContent(reply: String) = CodeTransformChatMessageContent( + message = reply, type = CodeTransformChatMessageType.Prompt, ) +fun buildPermissionToBuildChatContent() = CodeTransformChatMessageContent( + message = message("codemodernizer.chat.message.permission_to_build"), + type = CodeTransformChatMessageType.FinalizedAnswer, + buttons = listOf( + cancelUserSelectionButton, + agreeToLocalBuildButton + ) +) + fun buildCheckingValidProjectChatContent() = CodeTransformChatMessageContent( message = message("codemodernizer.chat.message.validation.check_eligible_modules"), type = CodeTransformChatMessageType.PendingAnswer, @@ -399,6 +416,11 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa type = CodeTransformChatMessageType.FinalizedAnswer, ) +fun buildPromptTargetJDKPathChatContent(prompt: String) = CodeTransformChatMessageContent( + message = prompt, + type = CodeTransformChatMessageType.FinalizedAnswer, +) + fun buildCustomDependencyVersionsFileValidChatContent() = CodeTransformChatMessageContent( message = "I received your .yaml file and will upload it to Q.", type = CodeTransformChatMessageType.FinalizedAnswer, 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 322f745a8fb..d6a8b6ac958 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 @@ -57,7 +57,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHi import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildLanguageUpgradeProjectValidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormIntroChatContent -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildObjectiveChosenChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectInvalidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationErrorChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationSuccessDetailsChatContent @@ -125,6 +125,13 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.testFramework.LightVirtualFile import org.jetbrains.yaml.YAMLFileType +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPermissionToBuildChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKPathChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD +import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt +import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformPreValidationError @@ -140,9 +147,16 @@ class CodeTransformChatController( private val telemetry = CodeTransformTelemetryManager.getInstance(context.project) override suspend fun processChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) { + if (chatSessionStorage.getSession(message.tabId).conversationState == CodeTransformConversationState.PROMPT_TARGET_JDK_PATH) { + // we are prompting user for target JDK path + processJDKPathChatPromptMessage(message) + return + } + + // otherwise, we are asking for transformation objective val objective = message.message.trim().lowercase() - codeTransformChatHelper.addNewMessage(buildObjectiveChosenChatContent(objective)) + codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(objective)) codeTransformChatHelper.sendChatInputEnabledMessage(message.tabId, false) codeTransformChatHelper.sendUpdatePlaceholderMessage(message.tabId, "Open a new tab to chat with Q") @@ -196,6 +210,7 @@ class CodeTransformChatController( } private suspend fun getUserObjective(tabId: String) { + chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_OBJECTIVE codeTransformChatHelper.addNewMessage(buildChooseTransformationObjectiveChatContent()) codeTransformChatHelper.sendChatInputEnabledMessage(tabId, true) codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, message("codemodernizer.chat.message.choose_objective_placeholder")) @@ -424,14 +439,52 @@ class CodeTransformChatController( val transformCapabilities = when (message.oneOrMultipleDiffsSelection) { message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs") -> listOf( EXPLAINABILITY_V1, + CLIENT_SIDE_BUILD, SELECTIVE_TRANSFORMATION_V1 ) else -> listOf( - EXPLAINABILITY_V1 + EXPLAINABILITY_V1, + CLIENT_SIDE_BUILD ) } telemetry.submitSelection(message.oneOrMultipleDiffsSelection) codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection)) + codeModernizerManager.codeTransformationSession?.let { + it.sessionContext.transformCapabilities = transformCapabilities + } + promptForTargetJdkPath(message.tabId) + // TODO: when custom 1P upgrades ready, delete line above and uncomment line below + // promptForCustomYamlFile() + } + + override suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) { + withContext(EDT) { + val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() + .withDescription("Select .yaml file") + .withExtensionFilter("yaml") + val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext + val isValid = validateYamlFile(selectedFile.readText()) + if (!isValid) { + codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent()) + codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) + return@withContext + } + codeModernizerManager.codeTransformationSession?.let { + it.sessionContext.customDependencyVersionsFile = selectedFile + } + codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent()) + promptForTargetJdkPath(message.tabId) + } + } + + private suspend fun processJDKPathChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) { + codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkPath = message.message.trim() + codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(message.message.trim())) + codeTransformChatHelper.addNewMessage(buildPermissionToBuildChatContent()) + } + + /* + private suspend fun promptForCustomYamlFile() { codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent()) val sampleYAML = """ name: "custom-dependency-management" @@ -457,44 +510,30 @@ dependencyManagement: ApplicationManager.getApplication().invokeLater { FileEditorManager.getInstance(context.project).openFile(virtualFile, true) } - codeModernizerManager.codeTransformationSession?.let { - it.sessionContext.transformCapabilities = transformCapabilities - } - } - - override suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) { - withContext(EDT) { - val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() - .withDescription("Select .yaml file") - .withExtensionFilter("yaml") - val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext - val isValid = validateYamlFile(selectedFile.readText()) - if (!isValid) { - codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent()) - codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) - return@withContext - } - codeModernizerManager.codeTransformationSession?.let { - it.sessionContext.customDependencyVersionsFile = selectedFile - } - codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent()) - codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) - codeModernizerManager.codeTransformationSession?.let { - codeModernizerManager.runLocalMavenBuild(context.project, it) - } - } } + */ override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) { codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent()) - // if user doesn't provide a custom .yaml file, just move on with local build - // TODO: potentially we want to ask user to provide target JDK path? + promptForTargetJdkPath(message.tabId) + } + + override suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild) { codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) codeModernizerManager.codeTransformationSession?.let { codeModernizerManager.runLocalMavenBuild(context.project, it) } } + private suspend fun promptForTargetJdkPath(tabId: String) { + chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_PATH + val targetJdk = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty() + val javaHomePrompt = createJavaHomePrompt(targetJdk) + codeTransformChatHelper.addNewMessage(buildPromptTargetJDKPathChatContent(javaHomePrompt)) + codeTransformChatHelper.sendChatInputEnabledMessage(tabId, true) + codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, "Enter the path to your Java installation") + } + private fun getSourceJdk(moduleConfigurationFile: VirtualFile): JavaSdkVersion { // this should never throw the RuntimeException since invalid JDK case is already handled in previous validation step val moduleJdkVersion = ModuleUtil.findModuleForFile(moduleConfigurationFile, context.project)?.tryGetJdk(context.project) 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 e8c58ac552e..7ddf17d2082 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 @@ -4,29 +4,52 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven import com.intellij.openapi.application.runInEdt +import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project -import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.idea.maven.execution.MavenRunner import org.jetbrains.idea.maven.execution.MavenRunnerParameters import org.jetbrains.idea.maven.execution.MavenRunnerSettings import org.slf4j.Logger import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.info +import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerSessionContext +import software.aws.toolkits.jetbrains.services.codemodernizer.model.MAVEN_BUILD_RUN_UNIT_TESTS import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenCopyCommandsResult import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenDependencyReportCommandsResult -import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.telemetry.CodeTransformBuildCommand import software.aws.toolkits.telemetry.Result import java.io.File import java.nio.file.Files import java.nio.file.Path +fun runClientSideBuild(targetDir: VirtualFile, logger: Logger, project: Project): Pair { + // run mvn test-compile or mvn test + val transformMvnRunner = TransformMavenRunner(project) + val mvnSettings = MavenRunner.getInstance(project).settings.clone() + val buildRunnable = runClientSideBuild(targetDir, mvnSettings, transformMvnRunner, logger, project) + buildRunnable.await() + // write build output to a new text file and open it + val buildLogOutput = buildRunnable.getOutput().toString() + // first line is a long Maven String showing the build command; not useful or needed + val outputWithoutFirstLine = buildLogOutput.lines().drop(1).joinToString("\n") + val buildLogOutputFile = Files.createTempFile("build-logs-", ".txt") + Files.write(buildLogOutputFile, outputWithoutFirstLine.toByteArray()) + val buildLogOutputVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(buildLogOutputFile.toFile()) + runInEdt { + if (buildLogOutputVirtualFile != null) { + FileEditorManager.getInstance(project).openFile(buildLogOutputVirtualFile, true) + } + } + return buildRunnable.exitCode to buildRunnable.getOutput().toString() +} + fun runHilMavenCopyDependency( context: CodeModernizerSessionContext, sourceFolder: File, @@ -82,12 +105,6 @@ fun runMavenCopyCommands( val transformMvnRunner = TransformMavenRunner(project) context.mavenRunnerQueue.add(transformMvnRunner) val mvnSettings = MavenRunner.getInstance(project).settings.clone() // clone required to avoid editing user settings - notifyStickyInfo("current jreName", mvnSettings.jreName) - mvnSettings.setJreName("corretto-21") - // use ProjectJdkTable.getInstance().allJdks to join all of the "name"s of the list - val jreNames = ProjectJdkTable.getInstance().allJdks.joinToString(", ") { it.name } - notifyStickyInfo("jreNames", jreNames) - val sourceVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(sourceFolder) val module = sourceVirtualFile?.let { ModuleUtilCore.findModuleForFile(it, project) } val moduleSdk = module?.let { ModuleRootManager.getInstance(it).sdk } @@ -198,6 +215,36 @@ private fun runMavenCopyDependencies( return copyTransformRunnable } +private fun runClientSideBuild( + targetDir: VirtualFile, + mvnSettings: MavenRunnerSettings, + transformMavenRunner: TransformMavenRunner, + logger: Logger, + project: Project +): TransformRunnable { + val customBuildCommand = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.customBuildCommand + val clientSideBuildCommand = if (customBuildCommand == MAVEN_BUILD_RUN_UNIT_TESTS) "test" else "test-compile" + val buildParams = MavenRunnerParameters( + false, + targetDir.path, + null, + listOf(clientSideBuildCommand), + null, + null + ) + val buildTransformRunnable = TransformRunnable() + runInEdt { + try { + CodeModernizerManager.getInstance(project).getMvnBuildWindow().show() + transformMavenRunner.run(buildParams, mvnSettings, buildTransformRunnable, true) + } catch (t: Throwable) { + logger.error(t) { "Maven Build: Unexpected error when executing bundled Maven $clientSideBuildCommand" } + buildTransformRunnable.setExitCode(Integer.MIN_VALUE) // to stop looking for the exitCode + } + } + return buildTransformRunnable +} + private fun runMavenClean( sourceFolder: File, buildlogBuilder: StringBuilder, @@ -212,7 +259,7 @@ private fun runMavenClean( sourceFolder.absolutePath, null, listOf("-Dmaven.repo.local=$destinationDir", "clean"), - emptyList(), + null, null ) val cleanTransformRunnable = TransformRunnable() @@ -248,7 +295,7 @@ private fun runMavenInstall( sourceFolder.absolutePath, null, flags, - emptyList(), + null, null ) val installTransformRunnable = TransformRunnable() @@ -284,7 +331,7 @@ private fun runMavenDependencyUpdatesReport( sourceFolder.absolutePath, null, dependencyUpdatesReportCommandList, - emptyList(), + null, null ) val dependencyUpdatesReportRunnable = TransformRunnable() diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt index a68c659ba6f..f071a071835 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt @@ -6,7 +6,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven import com.intellij.execution.process.ProcessAdapter import com.intellij.execution.process.ProcessEvent import com.intellij.execution.process.ProcessHandler -import com.intellij.execution.process.ProcessOutputTypes import com.intellij.execution.runners.ProgramRunner import com.intellij.execution.ui.RunContentDescriptor import com.intellij.openapi.fileEditor.FileDocumentManager @@ -15,17 +14,28 @@ import com.intellij.openapi.util.Key import org.jetbrains.idea.maven.execution.MavenRunConfigurationType import org.jetbrains.idea.maven.execution.MavenRunnerParameters import org.jetbrains.idea.maven.execution.MavenRunnerSettings +import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager +import com.intellij.openapi.projectRoots.ProjectJdkTable class TransformMavenRunner(val project: Project) { private var handler: ProcessHandler? = null + fun run(parameters: MavenRunnerParameters, settings: MavenRunnerSettings, onComplete: TransformRunnable, isClientSideBuild: Boolean = false) { + if (isClientSideBuild) { + // TODO: if we go with this implementation 1) consult UX and + // 2) run this check much sooner in chat with an appropriate error message if JDK is not found + val targetJdkPath = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.targetJdkPath + ?: throw RuntimeException("No target JDK path provided by user; cannot run client-side build") + val jdkTable = ProjectJdkTable.getInstance() + val targetJdkName = jdkTable.allJdks.find { it.homePath == targetJdkPath }?.name + ?: throw RuntimeException("Could not find user's target JDK; cannot run client-side build") + settings.setJreName(targetJdkName) + } - fun run(parameters: MavenRunnerParameters, settings: MavenRunnerSettings, onComplete: TransformRunnable) { FileDocumentManager.getInstance().saveAllDocuments() val callback = ProgramRunner.Callback { descriptor: RunContentDescriptor -> val handler = descriptor.processHandler this.handler = handler if (handler == null) { - // add log error here onComplete.setExitCode(-1) return@Callback } @@ -33,13 +43,9 @@ class TransformMavenRunner(val project: Project) { var output: String = "" override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) { - when (outputType) { - ProcessOutputTypes.STDOUT -> { - output += event.text - } - ProcessOutputTypes.STDERR -> { - output += event.text - } + // IntelliJ includes some unneeded lines in stdout; exclude those from build logs + if (!event.text.startsWith("[IJ]")) { + output += event.text } } @@ -49,8 +55,6 @@ class TransformMavenRunner(val project: Project) { } }) } - // Change runner from IntelliJ controlled to Maven controlled - // Setting isDelegateBuild = true allows us to set the JRE used by Maven during runtime MavenRunConfigurationType.runConfiguration(project, parameters, null, settings, callback, false) } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt index c4ab0e6fc44..7741306cb7c 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt @@ -4,7 +4,7 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven class TransformRunnable : Runnable { - private var exitCode: Int? = null + var exitCode: Int? = null private var output: String? = null fun setExitCode(i: Int) { 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 b26fcbaeae2..3e64f8b7442 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 @@ -21,6 +21,7 @@ enum class CodeTransformButtonId(val id: String) { SelectSQLModuleSchema("codetransform-input-select-sql-module-schema"), CancelTransformation("codetransform-input-cancel"), ContinueTransformation("codetransform-input-continue"), + AgreeToLocalBuild("codetransform-input-agree"), ConfirmSkipTests("codetransform-input-confirm-skip-tests"), ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"), ConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"), @@ -109,6 +110,10 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage { @JsonProperty("tabID") val tabId: String, ) : IncomingCodeTransformMessage + data class CodeTransformAgreeToLocalBuild( + @JsonProperty("tabID") val tabId: String, + ) : IncomingCodeTransformMessage + data class CodeTransformConfirmSkipTests( @JsonProperty("tabID") val tabId: String, val skipTestsSelection: String, diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt index 77f15eea0c3..1409559b139 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt @@ -25,7 +25,7 @@ fun getTransformationProgressStepsByTransformationStepId( if (progressStep != null) { val itemToAdd = BuildProgressTimelineStepDetailItem( progressStep.name(), - progressStep.description(), + progressStep.description().orEmpty(), mapTransformationPlanApiStatus(progressStep.status()), progressStep.startTime()?.toString(), progressStep.endTime()?.toString() 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 aed2867328d..288c20a4a50 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 @@ -46,9 +46,11 @@ const val MANIFEST_PATH = "manifest.json" const val ZIP_SOURCES_PATH = "sources" const val ZIP_DEPENDENCIES_PATH = "dependencies" const val BUILD_LOG_PATH = "build-logs.txt" +const val CUSTOM_DEPENDENCY_VERSIONS_FILE_PATH = "custom-upgrades.yaml" const val UPLOAD_ZIP_MANIFEST_VERSION = "1.0" const val HIL_1P_UPGRADE_CAPABILITY = "HIL_1pDependency_VersionUpgrade" const val EXPLAINABILITY_V1 = "EXPLAINABILITY_V1" +const val CLIENT_SIDE_BUILD = "CLIENT_SIDE_BUILD" const val MAVEN_CONFIGURATION_FILE_NAME = "pom.xml" const val MAVEN_BUILD_RUN_UNIT_TESTS = "clean test" const val MAVEN_BUILD_SKIP_UNIT_TESTS = "clean test-compile" @@ -67,7 +69,7 @@ data class CodeModernizerSessionContext( var configurationFile: VirtualFile? = null, // used to ZIP module val sourceJavaVersion: JavaSdkVersion, // always needed for startJob API val targetJavaVersion: JavaSdkVersion, // 17 or 21 - var transformCapabilities: List = listOf(EXPLAINABILITY_V1), + var transformCapabilities: List = listOf(), var customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS, // run unit tests by default val sourceVendor: String = ORACLE_DB, // only one supported val targetVendor: String? = null, @@ -75,6 +77,8 @@ data class CodeModernizerSessionContext( var schema: String? = null, val sqlMetadataZip: File? = null, var customDependencyVersionsFile: VirtualFile? = null, + var targetJdkPath: String? = null, + var originalUploadZipPath: Path? = null ) : Disposable { private val mapper = jacksonObjectMapper() private val ignoredDependencyFileExtensions = setOf(INVALID_SUFFIX_SHA, INVALID_SUFFIX_REPOSITORIES) @@ -269,7 +273,15 @@ data class CodeModernizerSessionContext( LOG.info { "Dependency files size = ${dependencyFiles.sumOf { it.length().toInt() }}" } - // 3) Sources + // 3) Custom YAML file + // TODO: where to put this? VS Code puts it in custom-upgrades/dependency-versions.yaml; here we put it at the root + if (customDependencyVersionsFile != null) { + customDependencyVersionsFile?.inputStream?.use { + zip.putNextEntry(Path(CUSTOM_DEPENDENCY_VERSIONS_FILE_PATH).toString(), it) + } + } + + // 4) Sources files?.forEach { file -> val relativePath = File(file.path).relativeTo(sourceFolder) val paddedPath = zipSources.resolve(relativePath) @@ -290,7 +302,7 @@ data class CodeModernizerSessionContext( LOG.info { "Source code files size = ${files?.sumOf { it.length.toInt() }}" } - // 4) Build Log + // 5) Initial Maven copy-deps / install build log buildLogBuilder.toString().byteInputStream().use { zip.putNextEntry(Path(BUILD_LOG_PATH).toString(), it) } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt new file mode 100644 index 00000000000..467c7c5b289 --- /dev/null +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt @@ -0,0 +1,10 @@ +// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.codemodernizer.model + +enum class CodeTransformConversationState { + PROMPT_OBJECTIVE, + PROMPT_TARGET_JDK_PATH, + IDLE, +} diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt index 9267de9ddb9..e5bb80ad77a 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt @@ -3,13 +3,14 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.model +// TODO: include custom yaml file path in manifest.json? data class ZipManifest( val sourcesRoot: String = ZIP_SOURCES_PATH, val dependenciesRoot: String = ZIP_DEPENDENCIES_PATH, val buildLogs: String = BUILD_LOG_PATH, val version: String = UPLOAD_ZIP_MANIFEST_VERSION, val hilCapabilities: List = listOf(HIL_1P_UPGRADE_CAPABILITY), - val transformCapabilities: List = listOf(EXPLAINABILITY_V1), + val transformCapabilities: List = listOf(EXPLAINABILITY_V1, CLIENT_SIDE_BUILD), val customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS, val requestedConversions: RequestedConversions? = null, // only used for SQL conversions for now ) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt index 28bd980c1aa..0f60b3ceb23 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt @@ -72,7 +72,7 @@ class BuildProgressStepDetailsPanel : JPanel(BorderLayout()) { it.description } else { if (it.status == BuildStepStatus.DONE) { - message("codemodernizer.migration_plan.substeps.description_succeed") + message("codemodernizer.migration_plan.substeps.description_completed") } else if (it.status == BuildStepStatus.ERROR) { message("codemodernizer.migration_plan.substeps.description_failed") } else { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt index f32c78f206c..550d3205705 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt @@ -3,9 +3,12 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.session +import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState + data class Session( val tabId: String, ) { var isAuthenticating: Boolean = false var authNeededNotified: Boolean = false + var conversationState: CodeTransformConversationState = CodeTransformConversationState.IDLE } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index 9ddc086d819..4f83182684c 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -4,6 +4,14 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.utils import com.fasterxml.jackson.module.kotlin.readValue +import com.intellij.openapi.application.runInEdt +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.diff.impl.patch.PatchReader +import com.intellij.openapi.diff.impl.patch.formove.PatchApplier +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.module.JavaModuleType +import com.intellij.openapi.module.ModuleManager import com.intellij.notification.NotificationAction import com.intellij.openapi.project.Project import com.intellij.serviceContainer.AlreadyDisposedException @@ -18,6 +26,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.TransformationPlan import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus +import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep import software.amazon.awssdk.services.codewhispererruntime.model.ValidationException import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException import software.aws.toolkits.core.utils.WaiterUnrecoverableException @@ -36,6 +45,17 @@ import software.aws.toolkits.resources.message import java.time.Duration import java.util.Locale import java.util.concurrent.atomic.AtomicBoolean +import com.intellij.openapi.util.io.FileUtil.createTempDirectory +import com.intellij.openapi.vfs.LocalFileSystem +import kotlinx.coroutines.withContext +import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUploadContext +import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext +import software.aws.toolkits.core.utils.getLogger +import software.aws.toolkits.jetbrains.core.coroutines.EDT +import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager +import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runClientSideBuild +import java.nio.file.Path +import java.nio.file.Paths data class PollingResult( val succeeded: Boolean, @@ -97,6 +117,9 @@ suspend fun JobId.pollTransformationStatusAndPlan( delay(sleepDurationMillis) newPlan = clientAdaptor.getCodeModernizationPlan(this).transformationPlan() } + if (newStatus == TransformationStatus.TRANSFORMING && newPlan != null) { + attemptLocalBuild(newPlan, this, project) + } if (newStatus != state) { telemetry.jobStatusChanged(this, newStatus.toString(), state.toString()) } @@ -144,6 +167,112 @@ suspend fun JobId.pollTransformationStatusAndPlan( return PollingResult(true, transformationResponse?.transformationJob(), state, transformationPlan) } +suspend fun attemptLocalBuild(plan: TransformationPlan, jobId: JobId, project: Project) { + val artifactId = getClientInstructionArtifactId(plan) + getLogger().info("Found artifactId: $artifactId") + if (artifactId != null) { + val clientInstructionsPath = downloadClientInstructions(jobId, artifactId, project) + getLogger().info("Downloaded client instructions for job ${jobId.id} and artifact $artifactId at: $clientInstructionsPath") + processClientInstructions(clientInstructionsPath, jobId, artifactId, project) + getLogger().info("Finished processing client instructions for job ${jobId.id} and artifact $artifactId") + } +} + +suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId, artifactId: String, project: Project) { + var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_${artifactId}", null).toPath() + getLogger().info("About to copy the original project ZIP to: $copyOfProjectSources") + val originalProjectZip = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.originalUploadZipPath + originalProjectZip?.let { unzipFile(it, copyOfProjectSources, isSqlMetadata = false, extractOnlySources = true) } + copyOfProjectSources = copyOfProjectSources.resolve("sources") // where the user's source code is within the upload ZIP + getLogger().info("Copied and unzipped original project sources to: $copyOfProjectSources") + + val targetDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(copyOfProjectSources.toFile()) + ?: throw RuntimeException("Cannot find copy of project sources directory") + + withContext(EDT) { + runWriteAction { + // create temp module with project copy so that we can apply diff.patch + val modifiableModel = ModuleManager.getInstance(project).getModifiableModel() + val tempModule = modifiableModel.newModule( + Paths.get(targetDir.path).resolve("temp.iml").toString(), + JavaModuleType.getModuleType().id + ) + + try { + val moduleModel = ModuleRootManager.getInstance(tempModule).modifiableModel + moduleModel.addContentEntry(targetDir.url) + moduleModel.commit() + modifiableModel.commit() + + // apply diff.patch + val patchReader = PatchReader(clientInstructionsPath) + patchReader.parseAllPatches() + PatchApplier( + project, + targetDir, + patchReader.allPatches, + null, + null + ).execute() + getLogger().info("Successfully applied patch file at $clientInstructionsPath") + + val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(clientInstructionsPath.toFile()) + ?: throw RuntimeException("Cannot find patch file at $clientInstructionsPath") + FileEditorManager.getInstance(project).openFile(virtualFile, true) + } catch (e: Exception) { + getLogger().error("Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " + + "$clientInstructionsPath: $e") + } finally { + runWriteAction { + ModuleManager.getInstance(project).disposeModule(tempModule) + } + } + } + } + + val (exitCode, buildOutput) = runClientSideBuild(targetDir, CodeModernizerManager.LOG, project) + getLogger().info("Ran client-side build with an exit code of $exitCode") + val uploadZip = createClientSideBuildUploadZip(exitCode, buildOutput) + getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}") + val uploadContext = UploadContext.fromTransformationUploadContext(TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build()) + getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId") + CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext) + getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now") + CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation() + uploadZip.deleteRecursively() + copyOfProjectSources.toFile().deleteRecursively() + getLogger().info("Deleted copy of project sources and client-side build upload ZIP") + // switch back to Transformation Hub view + runInEdt { + CodeModernizerManager.getInstance(project).getBottomToolWindow().show() + } +} + +suspend fun downloadClientInstructions(jobId: JobId, artifactId: String, project: Project): Path { + val exportDestination = "downloadClientInstructions_${jobId.id}_$artifactId" + val exportZipPath = createTempDirectory(exportDestination, null) + val client = GumbyClient.getInstance(project) + val downloadBytes = client.downloadExportResultArchive(jobId, artifactId) + val downloadZipPath = zipToPath(downloadBytes, exportZipPath.toPath()).first.toAbsolutePath() + unzipFile(downloadZipPath, exportZipPath.toPath()) + return exportZipPath.toPath().resolve("diff.patch") +} + +fun getClientInstructionArtifactId(plan: TransformationPlan): String? { + val steps = plan.transformationSteps().drop(1) + val progressUpdate = findDownloadArtifactProgressUpdate(steps) + val artifactId = progressUpdate?.downloadArtifacts()?.firstOrNull()?.downloadArtifactId() + return artifactId +} + +fun findDownloadArtifactProgressUpdate(transformationSteps: List) = + transformationSteps + .flatMap { it.progressUpdates().orEmpty() } + .firstOrNull { update -> + update.status().name == "AWAITING_CLIENT_ACTION" && + update.downloadArtifacts()?.firstOrNull()?.downloadArtifactId() != null + } + // "name" holds the ID of the corresponding plan step (where table will go) and "description" holds the plan data fun getTableMapping(stepZeroProgressUpdates: List): Map { if (stepZeroProgressUpdates.isNotEmpty()) { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt index 585bbb11877..8ca05bf3946 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt @@ -3,17 +3,21 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.utils +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import com.intellij.openapi.application.runReadAction import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.readText +import kotlinx.coroutines.withContext import software.aws.toolkits.core.utils.createParentDirectories +import software.aws.toolkits.core.utils.createTemporaryZipFile 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.core.utils.putNextEntry +import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager.Companion.LOG import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_ARTIFACT_DIR_NAME import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_ARTIFACT_POMFOLDER_DIR_NAME @@ -36,6 +40,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.util.content import software.aws.toolkits.resources.message import java.io.File import java.io.FileOutputStream +import java.nio.file.Files import java.nio.file.Path import java.util.zip.ZipFile import kotlin.io.path.Path @@ -61,6 +66,27 @@ fun filterOnlyParentFiles(filePaths: Set): List { return shortestRoots.toList() } +fun createClientSideBuildUploadZip(exitCode: Int?, stdout: String): File { + val mapper = jacksonObjectMapper() + val outputFile = createTemporaryZipFile { zip -> + val manifest = mapOf( + "capability" to "CLIENT_SIDE_BUILD", + "exitCode" to exitCode, + "commandLogFileName" to "build-output.log" + ) + mapper.writeValueAsString(manifest) + .byteInputStream() + .use { inputStream -> + zip.putNextEntry(Path("manifest.json").toString(), inputStream) + } + + stdout.byteInputStream().use { inputStream -> + zip.putNextEntry(Path("build-output.log").toString(), inputStream) + } + } + return outputFile.toFile() +} + /** * @description For every directory, check if any supported build files (pom.xml etc) exists. * If we find a valid build file, store it and stop further recursion. @@ -114,7 +140,7 @@ fun parseBuildFile(buildFile: VirtualFile?): String? { /** * Unzips a zip into a dir. Returns the true when successfully unzips the file pointed to by [zipFilePath] to [destDir] */ -fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false): Boolean { +fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false, extractOnlySources: Boolean = false): Boolean { if (!zipFilePath.exists()) return false val zipFile = ZipFile(zipFilePath.toFile()) zipFile.use { file -> @@ -122,6 +148,12 @@ fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false): .filterNot { it.isDirectory } .map { zipEntry -> var fileName = zipEntry.name + if (extractOnlySources) { + // used to copy just the source code for client-side build + if (!fileName.startsWith("sources")) { + return@map + } + } if (isSqlMetadata) { // when manually compressing ZIP files, the files get unzipped under a subdirectory where we extract them to, // this change puts the files directly under the root of the target directory, which is what we want @@ -137,6 +169,26 @@ fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false): return true } +suspend fun zipToPath(byteArrayList: List, outputDirPath: Path? = null): Pair { + val zipFilePath = withContext(getCoroutineBgContext()) { + if (outputDirPath == null) { + Files.createTempFile(null, ".zip") + } else { + Files.createTempFile(outputDirPath, null, ".zip") + } + } + var totalDownloadBytes = 0 + withContext(getCoroutineBgContext()) { + Files.newOutputStream(zipFilePath).use { + for (bytes in byteArrayList) { + it.write(bytes) + totalDownloadBytes += bytes.size + } + } + } + return zipFilePath to totalDownloadBytes +} + fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesReport { val reportFile = pathToXmlDependency.toFile() val report = XML_MAPPER.readValue(reportFile, DependencyUpdatesReport::class.java) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt index 5c8a01f20a9..9ae256b6f0d 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt @@ -83,3 +83,24 @@ fun String.toTransformationLanguage() = when (this) { "JDK_21" -> TransformationLanguage.JAVA_21 else -> TransformationLanguage.UNKNOWN_TO_SDK_VERSION } + +fun createJavaHomePrompt(jdkVersion: String): String { + var javaHomePrompt = "Enter the path to $jdkVersion.\n\n" + val os = System.getProperty("os.name").lowercase() + if (os.contains("windows")) { + javaHomePrompt += "To find the JDK path, run the following commands in a new terminal: `cd \"C:/Program Files/Java\"` and then `dir`. " + + "If you see your JDK version, run `cd ` and then `cd` to show the path." + } else if (os.contains("mac") || os.contains("darwin")) { + val version = when (jdkVersion) { + "JDK_1_8" -> "1.8" + "JDK_11" -> "11" + "JDK_17" -> "17" + "JDK_21" -> "21" + else -> "JAVA_VERSION" // shouldn't happen; we only support Java 8, 11, 17, and 21 + } + javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `/usr/libexec/java_home -v $version`" + } else { + javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `update-java-alternatives --list`" + } + return javaHomePrompt +} 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 633879f4872..2f6fc255672 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 @@ -4,10 +4,16 @@ package software.aws.toolkits.jetbrains.services.codemodernizer import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog +import com.intellij.openapi.vfs.VirtualFile import com.intellij.testFramework.LightVirtualFile +import java.util.zip.ZipOutputStream +import java.util.zip.ZipEntry +import java.io.FileOutputStream import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertFalse +import junit.framework.TestCase.assertTrue import kotlinx.coroutines.runBlocking +import org.jetbrains.idea.maven.execution.MavenRunnerSettings import org.junit.Before import org.junit.Test import org.mockito.Mockito.doAnswer @@ -30,8 +36,10 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransfo 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.InvalidTelemetryReason +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.ValidationResult +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.downloadClientInstructions import software.aws.toolkits.jetbrains.services.codemodernizer.utils.filterOnlyParentFiles import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile import software.aws.toolkits.telemetry.CodeTransformPreValidationError @@ -157,12 +165,22 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { val mockDownloadResult = listOf() doReturn(mockDownloadResult).whenever(clientAdaptorSpy) .downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS) - doReturn(Pair(exampleZipPath, 0)).whenever(handler).unzipToPath(mockDownloadResult) val result = handler.downloadArtifact(jobId, TransformationDownloadArtifactType.LOGS, false) verify(clientAdaptorSpy, times(1)).downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS) assertEquals(expected, result) } + @Test + fun `downloadClientInstructions downloads and extracts patch file`() = runBlocking { + val jobId = JobId("test-job-id") + val artifactId = "test-artifact-id" + val mockBytes = "mock content".toByteArray() + doReturn(mockBytes).whenever(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId) + val result = downloadClientInstructions(jobId, artifactId, project) + verify(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId) + assertEquals(result.fileName.toString(), "diff.patch") + } + @Test fun `CodeModernizerArtifact can process a valid zip file`() { val artifact = CodeModernizerArtifact.create(exampleZipPath.toAbsolutePath().toString()) @@ -196,6 +214,30 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { assert(tempDir.resolve(validZipPatchFilePath).exists()) } + @Test + fun `can unzip only sources folder`() { + val tempDir = createTempDirectory("test_zip") + val destDir = createTempDirectory("test_unzip") + // create test zip file with both source and non-source files + val zipPath = tempDir.resolve("test.zip") + ZipOutputStream(FileOutputStream(zipPath.toFile())).use { zos -> + zos.putNextEntry(ZipEntry("sources/Test.kt")) + zos.write("test content".toByteArray()) + zos.closeEntry() + + zos.putNextEntry(ZipEntry("other/Other.kt")) + zos.write("other content".toByteArray()) + zos.closeEntry() + } + + val result = unzipFile(zipPath, destDir, extractOnlySources = true) + assertTrue(result) + assertTrue(destDir.resolve("sources/Test.kt").exists()) + assertFalse(destDir.resolve("other/Other.kt").exists()) + tempDir.toFile().deleteRecursively() + destDir.toFile().deleteRecursively() + } + @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 a02cd5baa97..9c20dfa9b5d 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 @@ -313,7 +313,6 @@ open class CodeWhispererCodeModernizerTestBase( ) testSessionSpy = spy(CodeModernizerSession(testSessionContextSpy, 0, 0)) - doNothing().whenever(testSessionSpy).deleteUploadArtifact(any()) doReturn(Job()).whenever(codeModernizerManagerSpy).launchModernizationJob(any(), any()) testCodeModernizerArtifact = spy( diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index 74416f5d4f5..9722c6a47fc 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -6,6 +6,7 @@ import io.mockk.every import io.mockk.just import io.mockk.mockkStatic import io.mockk.runs +import java.util.zip.ZipFile import io.mockk.verify import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat @@ -17,11 +18,17 @@ import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import software.amazon.awssdk.services.codewhispererruntime.model.AccessDeniedException +import software.amazon.awssdk.services.codewhispererruntime.model.TransformationDownloadArtifact +import software.amazon.awssdk.services.codewhispererruntime.model.TransformationPlan import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus +import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createClientSideBuildUploadZip import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getClientInstructionArtifactId import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getTableMapping import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildFile import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan @@ -219,6 +226,99 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase assertThat(expected).isEqualTo(actual) } + @Test + fun `getClientInstructionArtifactId extracts artifact ID from transformation plan`() { + val step1 = TransformationStep.builder() + .name("name of step 1") + .description("description of step 1") + .build() + val step2 = TransformationStep.builder() + .name("name of step 2") + .description("description of step 2") + .build() + val step3 = TransformationStep.builder() + .name("name of step 3") + .description("description of step 3") + .progressUpdates( + TransformationProgressUpdate.builder() + .name("Requesting client-side build") + .status("AWAITING_CLIENT_ACTION") + .downloadArtifacts( + TransformationDownloadArtifact.builder() + .downloadArtifactId("id-123") + .build() + ) + .build() + ) + .build() + val plan = TransformationPlan.builder() + .transformationSteps(listOf(step1, step2, step3)) + .build() + + val actual = getClientInstructionArtifactId(plan) + assertThat(actual).isEqualTo("id-123") + } + + @Test + fun `getClientInstructionArtifactId returns null when no download artifacts present`() { + val step1 = TransformationStep.builder() + .name("name of step 1") + .description("description of step 1") + .build() + val step2 = TransformationStep.builder() + .name("name of step 2") + .description("description of step 2") + .progressUpdates( + TransformationProgressUpdate.builder() + .name("NOT requesting client-side build") + .status("NOT awaiting_client_action") + .build() + ) + .build() + val plan = TransformationPlan.builder() + .transformationSteps(listOf(step1, step2)) + .build() + + val actual = getClientInstructionArtifactId(plan) + assertThat(actual).isNull() + } + + @Test + fun `createClientSideBuildUploadZip creates zip with manifest and build output`() { + val exitCode = 0 + val stdout = "Build completed successfully" + val zipFile = createClientSideBuildUploadZip(exitCode, stdout) + ZipFile(zipFile).use { zip -> + val manifestEntry = zip.getEntry("manifest.json") + assertThat(manifestEntry).isNotNull + val manifestContent = zip.getInputStream(manifestEntry).bufferedReader().use { it.readText() } + assertThat(manifestContent).contains("\"capability\":\"CLIENT_SIDE_BUILD\"") + assertThat(manifestContent).contains("\"exitCode\":0") + assertThat(manifestContent).contains("\"commandLogFileName\":\"build-output.log\"") + val logEntry = zip.getEntry("build-output.log") + assertThat(logEntry).isNotNull + val logContent = zip.getInputStream(logEntry).bufferedReader().use { it.readText() } + assertThat(logContent).isEqualTo("Build completed successfully") + } + zipFile.delete() + } + + @Test + fun `createJavaHomePrompt returns Windows instructions when on Windows`() { + System.setProperty("os.name", "Windows 10") + val prompt = createJavaHomePrompt("JDK_11") + assertThat(prompt).contains("Enter the path to JDK_11") + assertThat(prompt).contains("cd \"C:/Program Files/Java\"") + } + + @Test + fun `createJavaHomePrompt returns Mac instructions with correct version`() { + System.setProperty("os.name", "Mac OS X") + val prompt = createJavaHomePrompt("JDK_11") + assertThat(prompt).contains("Enter the path to JDK_11") + assertThat(prompt).contains("/usr/libexec/java_home -v 11") + } + @Test fun `parseBuildFile can detect absolute paths in build file`() { val module = projectRule.module 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 00f759af458..d4b483635c9 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 @@ -267,8 +267,6 @@ export class CodeTransformChatConnector { tabType: 'codetransform', }) } else if (action.id === FormButtonIds.OpenMvnBuild) { - console.log('open_mvn_build') - this.sendMessageToExtension({ command: 'codetransform-open-mvn-build', tabID, @@ -286,6 +284,12 @@ export class CodeTransformChatConnector { tabID, tabType: 'codetransform', }) + } else if (action.id === FormButtonIds.CodeTransformInputAgree) { + this.sendMessageToExtension({ + command: 'codetransform-agree', + tabID, + tabType: 'codetransform', + }) } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) { this.sendMessageToExtension({ command: 'codetransform-confirm-skip-tests', 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 01486f01f2a..aa56bd48569 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts @@ -37,6 +37,7 @@ type MessageCommand = | 'codetransform-cancel' | 'codetransform-stop' | 'codetransform-continue' + | 'codetransform-agree' | 'codetransform-confirm-skip-tests' | 'codetransform-confirm-one-or-multiple-diffs' | 'codetransform-input-confirm-custom-dependency-versions' 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 22b913acf96..0c8e96247eb 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 @@ -9,6 +9,7 @@ export const enum FormButtonIds { CodeTransformInputSQLModuleSchema = 'codetransform-input-select-sql-module-schema', CodeTransformInputCancel = 'codetransform-input-cancel', CodeTransformInputContinue = 'codetransform-input-continue', + CodeTransformInputAgree = 'codetransform-input-agree', CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests', CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs', CodeTransformInputCustomDependencyVersions = 'codetransform-input-confirm-custom-dependency-versions', @@ -49,6 +50,7 @@ export const isFormButtonCodeTransform = (id: string): boolean => { id === FormButtonIds.CodeTransformInputSQLModuleSchema || id === FormButtonIds.CodeTransformInputSkipTests || id === FormButtonIds.CodeTransformInputContinue || + id === FormButtonIds.CodeTransformInputAgree || id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs || id === FormButtonIds.CodeTransformInputCustomDependencyVersions || id === FormButtonIds.CodeTransformViewDiff || 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 c7e667e7bc8..bb57dda2f4f 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -674,6 +674,7 @@ codemodernizer.chat.message.one_or_multiple_diffs=If you would like to update an 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} with my proposed changes. +codemodernizer.chat.message.permission_to_build=I will build your project on this machine throughout the transformation. 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}. @@ -754,7 +755,7 @@ codemodernizer.migration_plan.header.description=Plan to transform your module codemodernizer.migration_plan.header.title=Code Transformation plan by Amazon Q codemodernizer.migration_plan.substeps.description_failed=Build failed codemodernizer.migration_plan.substeps.description_stopped=Job is stopped -codemodernizer.migration_plan.substeps.description_succeed=Build succeeded +codemodernizer.migration_plan.substeps.description_completed=Build completed codemodernizer.migration_summary.header.title=Transformation summary codemodernizer.notification.info.download.started.content=Downloading the updated code codemodernizer.notification.info.download.started.title=Download Started From d1b0c60584be2045a3cb01f1ecf47d8512f7a0cd Mon Sep 17 00:00:00 2001 From: David Hasani Date: Wed, 16 Apr 2025 12:54:16 -0700 Subject: [PATCH 03/16] remove agree to local build form --- .../codemodernizer/CodeTransformChatApp.kt | 3 --- .../InboundAppMessagesHandler.kt | 2 -- .../constants/CodeTransformChatItems.kt | 17 ---------------- .../controller/CodeTransformChatController.kt | 20 +++++-------------- .../messages/CodeTransformMessage.kt | 5 ----- .../ui/apps/codeTransformChatConnector.ts | 6 ------ .../mynah-ui/src/mynah-ui/ui/commands.ts | 1 - .../src/mynah-ui/ui/forms/constants.ts | 2 -- 8 files changed, 5 insertions(+), 51 deletions(-) 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 c7c51457d50..584a3424607 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 @@ -46,7 +46,6 @@ private enum class CodeTransformMessageTypes(val type: String) { CodeTransformStop("codetransform-stop"), CodeTransformCancel("codetransform-cancel"), CodeTransformContinue("codetransform-continue"), - CodeTransformAgree("codetransform-agree"), CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"), CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"), CodeTransformNew("codetransform-new"), @@ -82,7 +81,6 @@ class CodeTransformChatApp : AmazonQApp { CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class, CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class, CodeTransformMessageTypes.CodeTransformContinue.type to IncomingCodeTransformMessage.CodeTransformContinue::class, - CodeTransformMessageTypes.CodeTransformAgree.type to IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild::class, CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class, CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class, CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class, @@ -196,7 +194,6 @@ class CodeTransformChatApp : AmazonQApp { is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message) is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message) is IncomingCodeTransformMessage.CodeTransformContinue -> inboundAppMessagesHandler.processCodeTransformContinueAction(message) - is IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild -> inboundAppMessagesHandler.processCodeTransformAgreeToLocalBuild(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 208a8ad67d3..434516178bd 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 @@ -13,8 +13,6 @@ interface InboundAppMessagesHandler { suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) - suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild) - suspend fun processCodeTransformStartAction(message: IncomingCodeTransformMessage.CodeTransformStart) suspend fun processCodeTransformSelectSQLMetadataAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata) 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 b408bcff53a..38a6d8a98d1 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 @@ -52,14 +52,6 @@ private val continueTransformationButton = Button( id = CodeTransformButtonId.ContinueTransformation.id, ) -// used to agree to local build -private val agreeToLocalBuildButton = Button( - keepCardAfterClick = false, - waitMandatoryFormItems = false, - text = "Agree", - id = CodeTransformButtonId.AgreeToLocalBuild.id, -) - private val confirmUserSelectionLanguageUpgradeButton = Button( keepCardAfterClick = false, waitMandatoryFormItems = true, @@ -295,15 +287,6 @@ fun buildUserReplyChatContent(reply: String) = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.Prompt, ) -fun buildPermissionToBuildChatContent() = CodeTransformChatMessageContent( - message = message("codemodernizer.chat.message.permission_to_build"), - type = CodeTransformChatMessageType.FinalizedAnswer, - buttons = listOf( - cancelUserSelectionButton, - agreeToLocalBuildButton - ) -) - fun buildCheckingValidProjectChatContent() = CodeTransformChatMessageContent( message = message("codemodernizer.chat.message.validation.check_eligible_modules"), type = CodeTransformChatMessageType.PendingAnswer, 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 d6a8b6ac958..7d643fc3c24 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 @@ -121,17 +121,10 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYam import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.testFramework.LightVirtualFile -import org.jetbrains.yaml.YAMLFileType -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPermissionToBuildChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKPathChatContent -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt -import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformPreValidationError @@ -480,7 +473,11 @@ class CodeTransformChatController( private suspend fun processJDKPathChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) { codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkPath = message.message.trim() codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(message.message.trim())) - codeTransformChatHelper.addNewMessage(buildPermissionToBuildChatContent()) + // start local build once we get target JDK path + codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) + codeModernizerManager.codeTransformationSession?.let { + codeModernizerManager.runLocalMavenBuild(context.project, it) + } } /* @@ -518,13 +515,6 @@ dependencyManagement: promptForTargetJdkPath(message.tabId) } - override suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild) { - codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) - codeModernizerManager.codeTransformationSession?.let { - codeModernizerManager.runLocalMavenBuild(context.project, it) - } - } - private suspend fun promptForTargetJdkPath(tabId: String) { chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_PATH val targetJdk = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty() 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 3e64f8b7442..b26fcbaeae2 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 @@ -21,7 +21,6 @@ enum class CodeTransformButtonId(val id: String) { SelectSQLModuleSchema("codetransform-input-select-sql-module-schema"), CancelTransformation("codetransform-input-cancel"), ContinueTransformation("codetransform-input-continue"), - AgreeToLocalBuild("codetransform-input-agree"), ConfirmSkipTests("codetransform-input-confirm-skip-tests"), ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"), ConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"), @@ -110,10 +109,6 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage { @JsonProperty("tabID") val tabId: String, ) : IncomingCodeTransformMessage - data class CodeTransformAgreeToLocalBuild( - @JsonProperty("tabID") val tabId: String, - ) : IncomingCodeTransformMessage - data class CodeTransformConfirmSkipTests( @JsonProperty("tabID") val tabId: String, val skipTestsSelection: String, 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 d4b483635c9..08d1335a03f 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 @@ -284,12 +284,6 @@ export class CodeTransformChatConnector { tabID, tabType: 'codetransform', }) - } else if (action.id === FormButtonIds.CodeTransformInputAgree) { - this.sendMessageToExtension({ - command: 'codetransform-agree', - tabID, - tabType: 'codetransform', - }) } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) { this.sendMessageToExtension({ command: 'codetransform-confirm-skip-tests', 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 aa56bd48569..01486f01f2a 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts @@ -37,7 +37,6 @@ type MessageCommand = | 'codetransform-cancel' | 'codetransform-stop' | 'codetransform-continue' - | 'codetransform-agree' | 'codetransform-confirm-skip-tests' | 'codetransform-confirm-one-or-multiple-diffs' | 'codetransform-input-confirm-custom-dependency-versions' 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 0c8e96247eb..22b913acf96 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 @@ -9,7 +9,6 @@ export const enum FormButtonIds { CodeTransformInputSQLModuleSchema = 'codetransform-input-select-sql-module-schema', CodeTransformInputCancel = 'codetransform-input-cancel', CodeTransformInputContinue = 'codetransform-input-continue', - CodeTransformInputAgree = 'codetransform-input-agree', CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests', CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs', CodeTransformInputCustomDependencyVersions = 'codetransform-input-confirm-custom-dependency-versions', @@ -50,7 +49,6 @@ export const isFormButtonCodeTransform = (id: string): boolean => { id === FormButtonIds.CodeTransformInputSQLModuleSchema || id === FormButtonIds.CodeTransformInputSkipTests || id === FormButtonIds.CodeTransformInputContinue || - id === FormButtonIds.CodeTransformInputAgree || id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs || id === FormButtonIds.CodeTransformInputCustomDependencyVersions || id === FormButtonIds.CodeTransformViewDiff || From edf97738cc996a267dea3563848a9768eae2ef47 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Wed, 16 Apr 2025 15:18:24 -0700 Subject: [PATCH 04/16] prompt for jdk name instead of path --- .../constants/CodeTransformChatItems.kt | 12 ++++- .../controller/CodeTransformChatController.kt | 44 ++++++++++++------- .../ideMaven/TransformMavenRunner.kt | 10 +---- .../model/CodeModernizerSessionContext.kt | 2 +- .../model/CodeTransformConversationState.kt | 2 +- .../utils/CodeTransformUtils.kt | 21 --------- .../CodeWhispererCodeModernizerUtilsTest.kt | 17 ------- .../resources/MessagesBundle.properties | 2 +- 8 files changed, 42 insertions(+), 68 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 38a6d8a98d1..3f294ec5714 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 @@ -399,11 +399,19 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa type = CodeTransformChatMessageType.FinalizedAnswer, ) -fun buildPromptTargetJDKPathChatContent(prompt: String) = CodeTransformChatMessageContent( - message = prompt, +fun buildPromptTargetJDKNameChatContent(version: String) = CodeTransformChatMessageContent( + // TODO: get this text reviewed by Allie + message = "Enter the name of your $version from Settings -> Project Structure -> SDKs.", type = CodeTransformChatMessageType.FinalizedAnswer, ) +fun buildInvalidTargetJdkNameChatContent(jdkName: String) = CodeTransformChatMessageContent( + // TODO: get this text reviewed by Allie + message = "I could not find '$jdkName' under Settings -> Project Structure -> SDKs. Please add the target JDK there and try again.", + type = CodeTransformChatMessageType.FinalizedAnswer, + followUps = listOf(startNewTransformFollowUp) +) + fun buildCustomDependencyVersionsFileValidChatContent() = CodeTransformChatMessageContent( message = "I received your .yaml file and will upload it to Q.", type = CodeTransformChatMessageType.FinalizedAnswer, 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 7d643fc3c24..16736007d84 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,6 +9,7 @@ import com.intellij.openapi.fileChooser.FileChooser import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.projectRoots.JavaSdkVersion +import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.readText @@ -54,6 +55,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.buildInvalidTargetJdkNameChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildLanguageUpgradeProjectValidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormIntroChatContent @@ -75,7 +77,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent 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.buildUserInputCustomDependencyVersionsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent @@ -121,10 +122,10 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYam import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKPathChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKNameChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState -import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt +import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformPreValidationError @@ -140,9 +141,9 @@ class CodeTransformChatController( private val telemetry = CodeTransformTelemetryManager.getInstance(context.project) override suspend fun processChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) { - if (chatSessionStorage.getSession(message.tabId).conversationState == CodeTransformConversationState.PROMPT_TARGET_JDK_PATH) { - // we are prompting user for target JDK path - processJDKPathChatPromptMessage(message) + if (chatSessionStorage.getSession(message.tabId).conversationState == CodeTransformConversationState.PROMPT_TARGET_JDK_NAME) { + // we are prompting user for target JDK name + processJDKNameChatPromptMessage(message) return } @@ -445,7 +446,7 @@ class CodeTransformChatController( codeModernizerManager.codeTransformationSession?.let { it.sessionContext.transformCapabilities = transformCapabilities } - promptForTargetJdkPath(message.tabId) + promptForTargetJdkName(message.tabId) // TODO: when custom 1P upgrades ready, delete line above and uncomment line below // promptForCustomYamlFile() } @@ -466,12 +467,22 @@ class CodeTransformChatController( it.sessionContext.customDependencyVersionsFile = selectedFile } codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent()) - promptForTargetJdkPath(message.tabId) + promptForTargetJdkName(message.tabId) } } - private suspend fun processJDKPathChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) { - codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkPath = message.message.trim() + private suspend fun processJDKNameChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) { + chatSessionStorage.getSession(message.tabId).conversationState = CodeTransformConversationState.IDLE + codeTransformChatHelper.sendChatInputEnabledMessage(message.tabId, false) + codeTransformChatHelper.sendUpdatePlaceholderMessage(message.tabId, "") + + val providedJdkName = message.message.trim().lowercase() + val targetJdkName = ProjectJdkTable.getInstance().allJdks.find { it.name.trim().lowercase() == providedJdkName }?.name + if (targetJdkName == null) { + codeTransformChatHelper.addNewMessage(buildInvalidTargetJdkNameChatContent(providedJdkName)) + return + } + codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkName = targetJdkName codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(message.message.trim())) // start local build once we get target JDK path codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent()) @@ -512,16 +523,15 @@ dependencyManagement: override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) { codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent()) - promptForTargetJdkPath(message.tabId) + promptForTargetJdkName(message.tabId) } - private suspend fun promptForTargetJdkPath(tabId: String) { - chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_PATH - val targetJdk = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty() - val javaHomePrompt = createJavaHomePrompt(targetJdk) - codeTransformChatHelper.addNewMessage(buildPromptTargetJDKPathChatContent(javaHomePrompt)) + private suspend fun promptForTargetJdkName(tabId: String) { + chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_NAME + val targetJdkVersion = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty() + codeTransformChatHelper.addNewMessage(buildPromptTargetJDKNameChatContent(targetJdkVersion)) codeTransformChatHelper.sendChatInputEnabledMessage(tabId, true) - codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, "Enter the path to your Java installation") + codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, "Enter the name of your $targetJdkVersion") } private fun getSourceJdk(moduleConfigurationFile: VirtualFile): JavaSdkVersion { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt index f071a071835..4590c529793 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt @@ -15,19 +15,13 @@ import org.jetbrains.idea.maven.execution.MavenRunConfigurationType import org.jetbrains.idea.maven.execution.MavenRunnerParameters import org.jetbrains.idea.maven.execution.MavenRunnerSettings import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager -import com.intellij.openapi.projectRoots.ProjectJdkTable class TransformMavenRunner(val project: Project) { private var handler: ProcessHandler? = null fun run(parameters: MavenRunnerParameters, settings: MavenRunnerSettings, onComplete: TransformRunnable, isClientSideBuild: Boolean = false) { if (isClientSideBuild) { - // TODO: if we go with this implementation 1) consult UX and - // 2) run this check much sooner in chat with an appropriate error message if JDK is not found - val targetJdkPath = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.targetJdkPath - ?: throw RuntimeException("No target JDK path provided by user; cannot run client-side build") - val jdkTable = ProjectJdkTable.getInstance() - val targetJdkName = jdkTable.allJdks.find { it.homePath == targetJdkPath }?.name - ?: throw RuntimeException("Could not find user's target JDK; cannot run client-side build") + val targetJdkName = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.targetJdkName + ?: throw RuntimeException("Could not find user's target JDK; cannot run client-side build") // should not happen; already validated earlier settings.setJreName(targetJdkName) } 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 288c20a4a50..8df6b979c05 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 @@ -77,7 +77,7 @@ data class CodeModernizerSessionContext( var schema: String? = null, val sqlMetadataZip: File? = null, var customDependencyVersionsFile: VirtualFile? = null, - var targetJdkPath: String? = null, + var targetJdkName: String? = null, var originalUploadZipPath: Path? = null ) : Disposable { private val mapper = jacksonObjectMapper() diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt index 467c7c5b289..0d4c73c208f 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt @@ -5,6 +5,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.model enum class CodeTransformConversationState { PROMPT_OBJECTIVE, - PROMPT_TARGET_JDK_PATH, + PROMPT_TARGET_JDK_NAME, IDLE, } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt index 9ae256b6f0d..5c8a01f20a9 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt @@ -83,24 +83,3 @@ fun String.toTransformationLanguage() = when (this) { "JDK_21" -> TransformationLanguage.JAVA_21 else -> TransformationLanguage.UNKNOWN_TO_SDK_VERSION } - -fun createJavaHomePrompt(jdkVersion: String): String { - var javaHomePrompt = "Enter the path to $jdkVersion.\n\n" - val os = System.getProperty("os.name").lowercase() - if (os.contains("windows")) { - javaHomePrompt += "To find the JDK path, run the following commands in a new terminal: `cd \"C:/Program Files/Java\"` and then `dir`. " + - "If you see your JDK version, run `cd ` and then `cd` to show the path." - } else if (os.contains("mac") || os.contains("darwin")) { - val version = when (jdkVersion) { - "JDK_1_8" -> "1.8" - "JDK_11" -> "11" - "JDK_17" -> "17" - "JDK_21" -> "21" - else -> "JAVA_VERSION" // shouldn't happen; we only support Java 8, 11, 17, and 21 - } - javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `/usr/libexec/java_home -v $version`" - } else { - javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `update-java-alternatives --list`" - } - return javaHomePrompt -} diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index 9722c6a47fc..d71b4c62321 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -25,7 +25,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType -import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createClientSideBuildUploadZip import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getClientInstructionArtifactId @@ -303,22 +302,6 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase zipFile.delete() } - @Test - fun `createJavaHomePrompt returns Windows instructions when on Windows`() { - System.setProperty("os.name", "Windows 10") - val prompt = createJavaHomePrompt("JDK_11") - assertThat(prompt).contains("Enter the path to JDK_11") - assertThat(prompt).contains("cd \"C:/Program Files/Java\"") - } - - @Test - fun `createJavaHomePrompt returns Mac instructions with correct version`() { - System.setProperty("os.name", "Mac OS X") - val prompt = createJavaHomePrompt("JDK_11") - assertThat(prompt).contains("Enter the path to JDK_11") - assertThat(prompt).contains("/usr/libexec/java_home -v 11") - } - @Test fun `parseBuildFile can detect absolute paths in build file`() { val module = projectRule.module 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 bb57dda2f4f..66f6307f935 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -674,7 +674,6 @@ codemodernizer.chat.message.one_or_multiple_diffs=If you would like to update an 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} with my proposed changes. -codemodernizer.chat.message.permission_to_build=I will build your project on this machine throughout the transformation. 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}. @@ -685,6 +684,7 @@ codemodernizer.chat.message.result.success=I successfully completed your transfo codemodernizer.chat.message.result.success.multiple_diffs=I successfully completed your transformation. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs. The transformation summary has details about the changes I'm proposing. 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. +// TODO: get text from Allie for this 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.skip_tests_form.run_tests=Run unit tests From d312c59dfd5f2dd2bb24b266bbe7e7c73a66ff83 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Wed, 16 Apr 2025 15:41:37 -0700 Subject: [PATCH 05/16] delete artifacts --- .../codemodernizer/utils/CodeTransformApiUtils.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index 4f83182684c..471d739072b 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -236,12 +236,15 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}") val uploadContext = UploadContext.fromTransformationUploadContext(TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build()) getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId") - CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext) - getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now") - CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation() - uploadZip.deleteRecursively() - copyOfProjectSources.toFile().deleteRecursively() - getLogger().info("Deleted copy of project sources and client-side build upload ZIP") + try { + CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext) + getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now") + CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation() + } finally { + uploadZip.deleteRecursively() + copyOfProjectSources.toFile().deleteRecursively() + getLogger().info("Deleted copy of project sources and client-side build upload ZIP") + } // switch back to Transformation Hub view runInEdt { CodeModernizerManager.getInstance(project).getBottomToolWindow().show() From 31c767462aff56b14cfee8454b6571d0dc6e0e11 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Thu, 17 Apr 2025 15:06:40 -0700 Subject: [PATCH 06/16] fix detekt --- .../codemodernizer/ArtifactHandler.kt | 1 - .../codemodernizer/CodeModernizerSession.kt | 2 +- .../codemodernizer/CodeTransformChatApp.kt | 3 +- .../constants/CodeTransformChatItems.kt | 6 +-- .../controller/CodeTransformChatController.kt | 15 +++---- .../ideMaven/MavenRunnerUtils.kt | 2 +- .../model/CodeModernizerSessionContext.kt | 3 +- .../utils/CodeTransformApiUtils.kt | 44 ++++++++++--------- .../CodeWhispererCodeModernizerTest.kt | 2 - .../CodeWhispererCodeModernizerUtilsTest.kt | 7 +-- .../resources/MessagesBundle.properties | 5 ++- 11 files changed, 45 insertions(+), 45 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 6623f19ffa9..ab4af2a8d4c 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 @@ -24,7 +24,6 @@ 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 import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_ERROR_OVERVIEW 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 828b36d7db8..b19bd8e1fcf 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 @@ -423,7 +423,7 @@ class CodeModernizerSession( createUploadUrlResponse.kmsKeyArn().orEmpty(), ) { shouldStop.get() } } - LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of ${uploadContext.toString()}" } + LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of $uploadContext" } if (!shouldStop.get()) { LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())} ms" } } 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 584a3424607..edbf0afa7be 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 @@ -76,7 +76,8 @@ class CodeTransformChatApp : AmazonQApp { CodeTransformMessageTypes.Transform.type to IncomingCodeTransformMessage.Transform::class, CodeTransformMessageTypes.CodeTransformStart.type to IncomingCodeTransformMessage.CodeTransformStart::class, CodeTransformMessageTypes.CodeTransformSelectSQLMetadata.type to IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata::class, - CodeTransformMessageTypes.CodeTransformConfirmCustomDependencyVersions.type to IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions::class, + CodeTransformMessageTypes.CodeTransformConfirmCustomDependencyVersions.type to + IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions::class, CodeTransformMessageTypes.CodeTransformSelectSQLModuleSchema.type to IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema::class, CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class, CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class, 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 3f294ec5714..946ce58449b 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 @@ -400,14 +400,12 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa ) fun buildPromptTargetJDKNameChatContent(version: String) = CodeTransformChatMessageContent( - // TODO: get this text reviewed by Allie - message = "Enter the name of your $version from Settings -> Project Structure -> SDKs.", + message = message("codemodernizer.chat.message.enter_jdk_name", version), type = CodeTransformChatMessageType.FinalizedAnswer, ) fun buildInvalidTargetJdkNameChatContent(jdkName: String) = CodeTransformChatMessageContent( - // TODO: get this text reviewed by Allie - message = "I could not find '$jdkName' under Settings -> Project Structure -> SDKs. Please add the target JDK there and try again.", + message = message("codemodernizer.chat.message.enter_jdk_name_error", jdkName), type = CodeTransformChatMessageType.FinalizedAnswer, followUps = listOf(startNewTransformFollowUp) ) 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 16736007d84..cc0505daa8c 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 @@ -36,7 +36,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFO 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 -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.FEATURE_NAME import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildAbsolutePathWarning import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCheckingValidProjectChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildChooseTransformationObjectiveChatContent @@ -59,8 +58,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildIn import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildLanguageUpgradeProjectValidChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormIntroChatContent -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectInvalidChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKNameChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationErrorChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationSuccessDetailsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationSuccessIntroChatContent @@ -85,15 +84,19 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUs import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputSkipTestsFlagChatIntroContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserLanguageUpgradeSelectionSummaryChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserOneOrMultipleDiffsSelectionChatContent +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSQLConversionSelectionSummaryChatContent 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.FEATURE_NAME 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.CodeTransformCommandMessage import software.aws.toolkits.jetbrains.services.codemodernizer.messages.IncomingCodeTransformMessage +import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD 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.CodeTransformConversationState import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformHilDownloadArtifact import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType import software.aws.toolkits.jetbrains.services.codemodernizer.model.CustomerSelection @@ -122,10 +125,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYam import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType -import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKNameChatContent -import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD -import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState -import software.aws.toolkits.jetbrains.utils.notifyStickyInfo import software.aws.toolkits.resources.message import software.aws.toolkits.telemetry.CodeTransformPreValidationError @@ -491,7 +490,7 @@ class CodeTransformChatController( } } - /* +/* private suspend fun promptForCustomYamlFile() { codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent()) val sampleYAML = """ @@ -519,7 +518,7 @@ dependencyManagement: FileEditorManager.getInstance(context.project).openFile(virtualFile, true) } } - */ +*/ override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) { codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent()) 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 7ddf17d2082..2168e00eb23 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 @@ -220,7 +220,7 @@ private fun runClientSideBuild( mvnSettings: MavenRunnerSettings, transformMavenRunner: TransformMavenRunner, logger: Logger, - project: Project + project: Project, ): TransformRunnable { val customBuildCommand = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.customBuildCommand val clientSideBuildCommand = if (customBuildCommand == MAVEN_BUILD_RUN_UNIT_TESTS) "test" else "test-compile" 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 8df6b979c05..93bf8a20b1a 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 @@ -17,7 +17,6 @@ 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.TransformMavenRunner @@ -78,7 +77,7 @@ data class CodeModernizerSessionContext( val sqlMetadataZip: File? = null, var customDependencyVersionsFile: VirtualFile? = null, var targetJdkName: String? = null, - var originalUploadZipPath: Path? = null + var originalUploadZipPath: Path? = null, ) : Disposable { private val mapper = jacksonObjectMapper() private val ignoredDependencyFileExtensions = setOf(INVALID_SUFFIX_SHA, INVALID_SUFFIX_REPOSITORIES) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index 471d739072b..687a9c68ee6 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -4,18 +4,21 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.utils import com.fasterxml.jackson.module.kotlin.readValue +import com.intellij.notification.NotificationAction import com.intellij.openapi.application.runInEdt -import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.diff.impl.patch.PatchReader import com.intellij.openapi.diff.impl.patch.formove.PatchApplier -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.module.JavaModuleType import com.intellij.openapi.module.ModuleManager -import com.intellij.notification.NotificationAction import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.util.io.FileUtil.createTempDirectory +import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.serviceContainer.AlreadyDisposedException import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext import software.amazon.awssdk.awscore.exception.AwsServiceException import software.amazon.awssdk.services.codewhispererruntime.model.AccessDeniedException import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException @@ -27,35 +30,32 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep +import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUploadContext +import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext import software.amazon.awssdk.services.codewhispererruntime.model.ValidationException import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException +import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.WaiterUnrecoverableException import software.aws.toolkits.core.utils.Waiters.waitUntil -import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager +import software.aws.toolkits.jetbrains.core.coroutines.EDT import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient +import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager +import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener import software.aws.toolkits.jetbrains.services.codemodernizer.constants.BILLING_RATE import software.aws.toolkits.jetbrains.services.codemodernizer.constants.JOB_STATISTICS_TABLE_KEY +import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runClientSideBuild import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact.Companion.MAPPER import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.model.PlanTable import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.resources.message +import java.nio.file.Path +import java.nio.file.Paths import java.time.Duration import java.util.Locale import java.util.concurrent.atomic.AtomicBoolean -import com.intellij.openapi.util.io.FileUtil.createTempDirectory -import com.intellij.openapi.vfs.LocalFileSystem -import kotlinx.coroutines.withContext -import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUploadContext -import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext -import software.aws.toolkits.core.utils.getLogger -import software.aws.toolkits.jetbrains.core.coroutines.EDT -import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager -import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runClientSideBuild -import java.nio.file.Path -import java.nio.file.Paths data class PollingResult( val succeeded: Boolean, @@ -179,7 +179,7 @@ suspend fun attemptLocalBuild(plan: TransformationPlan, jobId: JobId, project: P } suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId, artifactId: String, project: Project) { - var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_${artifactId}", null).toPath() + var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_$artifactId", null).toPath() getLogger().info("About to copy the original project ZIP to: $copyOfProjectSources") val originalProjectZip = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.originalUploadZipPath originalProjectZip?.let { unzipFile(it, copyOfProjectSources, isSqlMetadata = false, extractOnlySources = true) } @@ -220,8 +220,10 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId ?: throw RuntimeException("Cannot find patch file at $clientInstructionsPath") FileEditorManager.getInstance(project).openFile(virtualFile, true) } catch (e: Exception) { - getLogger().error("Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " + - "$clientInstructionsPath: $e") + getLogger().error( + "Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " + + "$clientInstructionsPath: $e" + ) } finally { runWriteAction { ModuleManager.getInstance(project).disposeModule(tempModule) @@ -234,7 +236,9 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId getLogger().info("Ran client-side build with an exit code of $exitCode") val uploadZip = createClientSideBuildUploadZip(exitCode, buildOutput) getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}") - val uploadContext = UploadContext.fromTransformationUploadContext(TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build()) + val uploadContext = UploadContext.fromTransformationUploadContext( + TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build() + ) getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId") try { CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext) 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 2f6fc255672..99d59891d09 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 @@ -4,7 +4,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog -import com.intellij.openapi.vfs.VirtualFile import com.intellij.testFramework.LightVirtualFile import java.util.zip.ZipOutputStream import java.util.zip.ZipEntry @@ -13,7 +12,6 @@ import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue import kotlinx.coroutines.runBlocking -import org.jetbrains.idea.maven.execution.MavenRunnerSettings import org.junit.Before import org.junit.Test import org.mockito.Mockito.doAnswer diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index d71b4c62321..eebcef29f33 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -2,12 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 package software.aws.toolkits.jetbrains.services.codemodernizer + import io.mockk.every import io.mockk.just import io.mockk.mockkStatic import io.mockk.runs -import java.util.zip.ZipFile import io.mockk.verify +import kotlin.io.path.createTempFile import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat import org.junit.Before @@ -33,12 +34,12 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildF import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata -import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile +import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.jetbrains.utils.rules.addFileToModule import software.aws.toolkits.resources.message import java.util.concurrent.atomic.AtomicBoolean -import kotlin.io.path.createTempFile +import java.util.zip.ZipFile class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase() { @Before 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 66f6307f935..8f1a0d07c0e 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -647,6 +647,8 @@ codemodernizer.chat.message.download_failed_invalid_artifact=Sorry, I was unable codemodernizer.chat.message.download_failed_other=Sorry, I ran into an issue while trying to download your {0}. Please try again. {1} codemodernizer.chat.message.download_failed_ssl=Sorry, I couldn''t download your {0} because of an issue with your certificate. Please make sure all your certificates for your proxy client have been set up correctly for your IDE. codemodernizer.chat.message.download_failed_wildcard=Sorry, I couldn''t download your {0} because of an issue with your proxy client. Please check your IDE proxy settings and remove any wildcard (*) references, then restart your IDE. +codemodernizer.chat.message.enter_jdk_name=Enter the name of the {0} you are using. You can find the name in Settings > Project Structure > Platform Settings > SDKs. If you do not see the name of your JDK in the SDK settings, add your JDK, and then return to this chat and enter the name here. +codemodernizer.chat.message.enter_jdk_name_error=I could not find "{0}" in Settings > Project Structure > Platform Settings > SDKs. Please add the target JDK there and try again. codemodernizer.chat.message.error_request=Request failed codemodernizer.chat.message.follow_up.new_transformation=Start a new transformation codemodernizer.chat.message.hil.cannot_resume=I ran into an issue trying to resume your transformation. @@ -684,8 +686,7 @@ codemodernizer.chat.message.result.success=I successfully completed your transfo codemodernizer.chat.message.result.success.multiple_diffs=I successfully completed your transformation. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs. The transformation summary has details about the changes I'm proposing. 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. -// TODO: get text from Allie for this -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=I will build generated code in your local environment, not on the server side. For information on how I scan code to reduce security risks associated with building the code in your local environment, see the [Amazon Q Developer documentation](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/code-transformation.html#java-local-builds).\n\nI will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`. codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module. codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests From 530d63baabb25e2359f7c2917f6dfa485dc2d4bd Mon Sep 17 00:00:00 2001 From: David Hasani Date: Thu, 24 Apr 2025 15:37:11 -0700 Subject: [PATCH 07/16] final CSB commit --- .../constants/CodeTransformChatItems.kt | 4 ++-- .../controller/CodeTransformChatController.kt | 19 +++++++-------- .../codemodernizer/model/ZipManifest.kt | 3 ++- .../utils/CodeTransformApiUtils.kt | 5 +++- .../resources/MessagesBundle.properties | 6 ++--- .../transformTests/TransformChatTest.kt | 23 ++++++++++++++++++- 6 files changed, 43 insertions(+), 17 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 946ce58449b..5800c9ff5ad 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 @@ -89,7 +89,7 @@ private val confirmOneOrMultipleDiffsSelectionButton = Button( private val confirmCustomDependencyVersionsButton = Button( keepCardAfterClick = true, - waitMandatoryFormItems = true, // TODO: what does this do? + waitMandatoryFormItems = true, text = "Select file", id = CodeTransformButtonId.ConfirmCustomDependencyVersions.id, ) @@ -396,7 +396,7 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa confirmCustomDependencyVersionsButton, continueTransformationButton, ), - type = CodeTransformChatMessageType.FinalizedAnswer, + type = CodeTransformChatMessageType.PendingAnswer, ) fun buildPromptTargetJDKNameChatContent(version: String) = CodeTransformChatMessageContent( 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 cc0505daa8c..461c6552cbd 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 @@ -4,18 +4,22 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.controller import com.intellij.ide.BrowserUtil +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runInEdt import com.intellij.openapi.fileChooser.FileChooser import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.readText +import com.intellij.testFramework.LightVirtualFile import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import org.jetbrains.yaml.YAMLFileType import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.error @@ -76,6 +80,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent 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.buildUserInputCustomDependencyVersionsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent @@ -93,7 +98,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.messages.Authenti import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessage 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.CLIENT_SIDE_BUILD 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.CodeTransformConversationState @@ -430,23 +434,22 @@ class CodeTransformChatController( override suspend fun processCodeTransformOneOrMultipleDiffs(message: IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs) { val transformCapabilities = when (message.oneOrMultipleDiffsSelection) { + // TODO: add CLIENT_SIDE_BUILD to both below when releasing CSB message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs") -> listOf( EXPLAINABILITY_V1, - CLIENT_SIDE_BUILD, SELECTIVE_TRANSFORMATION_V1 ) else -> listOf( EXPLAINABILITY_V1, - CLIENT_SIDE_BUILD ) } telemetry.submitSelection(message.oneOrMultipleDiffsSelection) codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection)) codeModernizerManager.codeTransformationSession?.let { it.sessionContext.transformCapabilities = transformCapabilities + codeModernizerManager.runLocalMavenBuild(context.project, it) } - promptForTargetJdkName(message.tabId) - // TODO: when custom 1P upgrades ready, delete line above and uncomment line below + // TODO: when releasing CSB, delete "runLocalMavenBuild" line above and uncomment line below // promptForCustomYamlFile() } @@ -458,14 +461,14 @@ class CodeTransformChatController( val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext val isValid = validateYamlFile(selectedFile.readText()) if (!isValid) { - codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent()) + codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent()) codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) return@withContext } codeModernizerManager.codeTransformationSession?.let { it.sessionContext.customDependencyVersionsFile = selectedFile } - codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent()) + codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileValidChatContent()) promptForTargetJdkName(message.tabId) } } @@ -490,7 +493,6 @@ class CodeTransformChatController( } } -/* private suspend fun promptForCustomYamlFile() { codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent()) val sampleYAML = """ @@ -518,7 +520,6 @@ dependencyManagement: FileEditorManager.getInstance(context.project).openFile(virtualFile, true) } } -*/ override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) { codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent()) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt index e5bb80ad77a..e65b08f7e12 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt @@ -10,7 +10,8 @@ data class ZipManifest( val buildLogs: String = BUILD_LOG_PATH, val version: String = UPLOAD_ZIP_MANIFEST_VERSION, val hilCapabilities: List = listOf(HIL_1P_UPGRADE_CAPABILITY), - val transformCapabilities: List = listOf(EXPLAINABILITY_V1, CLIENT_SIDE_BUILD), + // TODO: add CLIENT_SIDE_BUILD to transformCapabilities when releasing CSB + val transformCapabilities: List = listOf(EXPLAINABILITY_V1), val customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS, val requestedConversions: RequestedConversions? = null, // only used for SQL conversions for now ) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index 687a9c68ee6..722591d5c30 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -64,6 +64,8 @@ data class PollingResult( val transformationPlan: TransformationPlan?, ) +private const val isClientSideBuildEnabled = false + /** * Wrapper around [waitUntil] that polls the API DescribeMigrationJob to check the migration job status. */ @@ -117,7 +119,8 @@ suspend fun JobId.pollTransformationStatusAndPlan( delay(sleepDurationMillis) newPlan = clientAdaptor.getCodeModernizationPlan(this).transformationPlan() } - if (newStatus == TransformationStatus.TRANSFORMING && newPlan != null) { + // TODO: remove flag when releasing CSB + if (isClientSideBuildEnabled && newStatus == TransformationStatus.TRANSFORMING && newPlan != null) { attemptLocalBuild(newPlan, this, project) } if (newStatus != state) { 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 8f1a0d07c0e..6ded544b51d 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -647,8 +647,8 @@ codemodernizer.chat.message.download_failed_invalid_artifact=Sorry, I was unable codemodernizer.chat.message.download_failed_other=Sorry, I ran into an issue while trying to download your {0}. Please try again. {1} codemodernizer.chat.message.download_failed_ssl=Sorry, I couldn''t download your {0} because of an issue with your certificate. Please make sure all your certificates for your proxy client have been set up correctly for your IDE. codemodernizer.chat.message.download_failed_wildcard=Sorry, I couldn''t download your {0} because of an issue with your proxy client. Please check your IDE proxy settings and remove any wildcard (*) references, then restart your IDE. -codemodernizer.chat.message.enter_jdk_name=Enter the name of the {0} you are using. You can find the name in Settings > Project Structure > Platform Settings > SDKs. If you do not see the name of your JDK in the SDK settings, add your JDK, and then return to this chat and enter the name here. -codemodernizer.chat.message.enter_jdk_name_error=I could not find "{0}" in Settings > Project Structure > Platform Settings > SDKs. Please add the target JDK there and try again. +codemodernizer.chat.message.enter_jdk_name=Enter the name of the {0} you are using. You can find the name in File > Project Structure > Platform Settings > SDKs. If you do not see the name of your JDK in the SDK settings, add your JDK, and then return to this chat and enter the name here. +codemodernizer.chat.message.enter_jdk_name_error=I could not find "{0}" in File > Project Structure > Platform Settings > SDKs. Please add the target JDK there and try again. codemodernizer.chat.message.error_request=Request failed codemodernizer.chat.message.follow_up.new_transformation=Start a new transformation codemodernizer.chat.message.hil.cannot_resume=I ran into an issue trying to resume your transformation. @@ -686,7 +686,7 @@ codemodernizer.chat.message.result.success=I successfully completed your transfo codemodernizer.chat.message.result.success.multiple_diffs=I successfully completed your transformation. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs. The transformation summary has details about the changes I'm proposing. 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 generated code in your local environment, not on the server side. For information on how I scan code to reduce security risks associated with building the code in your local environment, see the [Amazon Q Developer documentation](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/code-transformation.html#java-local-builds).\n\nI will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`. +codemodernizer.chat.message.skip_tests=I will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`. codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module. codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests diff --git a/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt b/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt index c51be54d50f..82951c22738 100644 --- a/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt +++ b/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt @@ -81,7 +81,25 @@ async function testNavigation() { const button = document.querySelector('button[action-id="codetransform-input-confirm-one-or-multiple-diffs"]') button.click() }) - +/* + const selectCustomVersionsForm = await page.waitForSelector('button[action-id="codetransform-input-confirm-custom-dependency-versions"]', { + timeout: 5000 + }) + console.log('Custom dependency versions file form appeared:', selectCustomVersionsForm !== null) + + await page.evaluate(() => { + const button = document.querySelector('button[action-id="codetransform-input-continue"]') + button.click() + }) + + await page.type('.mynah-chat-prompt-input', 'dummy-target-jdk-name-here') + await page.keyboard.press('Enter') + + const errorMessage = await page.waitForSelector('text/I could not find "dummy-target-jdk-name-here" in File > Project Structure > Platform Settings > SDKs.', { + timeout: 5000 + }) +*/ + // TODO: delete errorMessage below, and uncomment the above when releasing CSB const errorMessage = await page.waitForSelector('text/Sorry, I couldn\'t run the Maven clean install command', { timeout: 5000 }) @@ -149,6 +167,9 @@ class TransformChatTest { "Skip tests form appeared: true", "One or multiple diffs form appeared: true", "couldn't run the Maven clean install command" + // TODO: delete line above, and uncomment lines below when releasing CSB + // "I could not find \"dummy-target-jdk-name-here\"", + // "Custom dependency versions file form appeared: true", ) } } From 398ba578e8c2a5b8917d813629e63f053f3c7426 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Thu, 24 Apr 2025 16:12:34 -0700 Subject: [PATCH 08/16] fix detekt --- .../controller/CodeTransformChatController.kt | 13 +++++-------- .../codemodernizer/model/CustomerSelection.kt | 3 ++- .../codemodernizer/utils/CodeTransformApiUtils.kt | 10 +++++----- .../CodeWhispererCodeModernizerTest.kt | 6 +++--- .../CodeWhispererCodeModernizerUtilsTest.kt | 2 +- 5 files changed, 16 insertions(+), 18 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 461c6552cbd..4ce408528c1 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 @@ -4,22 +4,18 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.controller import com.intellij.ide.BrowserUtil -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runInEdt import com.intellij.openapi.fileChooser.FileChooser import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory -import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.readText -import com.intellij.testFramework.LightVirtualFile import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext -import org.jetbrains.yaml.YAMLFileType import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.error @@ -40,6 +36,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFO 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 +import software.aws.toolkits.jetbrains.services.codemodernizer.constants.FEATURE_NAME import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildAbsolutePathWarning import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCheckingValidProjectChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildChooseTransformationObjectiveChatContent @@ -80,7 +77,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent 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.buildUserInputCustomDependencyVersionsChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent @@ -93,7 +89,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUs import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSQLConversionSelectionSummaryChatContent 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.FEATURE_NAME 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.CodeTransformCommandMessage @@ -493,6 +488,8 @@ class CodeTransformChatController( } } + // TODO: uncomment when releasing CSB +/* private suspend fun promptForCustomYamlFile() { codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent()) val sampleYAML = """ @@ -512,7 +509,7 @@ dependencyManagement: - identifier: "com.example.plugin" targetVersion: "1.2.0" versionProperty: "plugin.version" # Optional -""".trimIndent() + """.trimIndent() val virtualFile = LightVirtualFile("sample-dependency-management.yaml", YAMLFileType.YML, sampleYAML) virtualFile.isWritable = true @@ -520,7 +517,7 @@ dependencyManagement: FileEditorManager.getInstance(context.project).openFile(virtualFile, true) } } - +*/ override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) { codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent()) promptForTargetJdkName(message.tabId) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt index d5e1ea24962..5c9828a1e0e 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt @@ -15,6 +15,7 @@ data class CustomerSelection( val targetVendor: String? = null, val sourceServerName: String? = null, val sqlMetadataZip: File? = null, - // note: schema / customBuildCommand / customDependencyVersionsFile are passed in to CodeModernizerSessionContext separately, + // note: schema / customBuildCommand / customDependencyVersionsFile / targetJdkName / originalUploadZipPath + // are passed in to CodeModernizerSessionContext separately, // *after* CodeModernizerSession is created ) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index 722591d5c30..6c010c39af6 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -34,13 +34,13 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext import software.amazon.awssdk.services.codewhispererruntime.model.ValidationException import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException -import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.WaiterUnrecoverableException import software.aws.toolkits.core.utils.Waiters.waitUntil +import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.jetbrains.core.coroutines.EDT -import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager +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.BILLING_RATE import software.aws.toolkits.jetbrains.services.codemodernizer.constants.JOB_STATISTICS_TABLE_KEY @@ -64,7 +64,7 @@ data class PollingResult( val transformationPlan: TransformationPlan?, ) -private const val isClientSideBuildEnabled = false +private const val IS_CLIENT_SIDE_BUILD_ENABLED = false /** * Wrapper around [waitUntil] that polls the API DescribeMigrationJob to check the migration job status. @@ -120,7 +120,7 @@ suspend fun JobId.pollTransformationStatusAndPlan( newPlan = clientAdaptor.getCodeModernizationPlan(this).transformationPlan() } // TODO: remove flag when releasing CSB - if (isClientSideBuildEnabled && newStatus == TransformationStatus.TRANSFORMING && newPlan != null) { + if (IS_CLIENT_SIDE_BUILD_ENABLED && newStatus == TransformationStatus.TRANSFORMING && newPlan != null) { attemptLocalBuild(newPlan, this, project) } if (newStatus != state) { @@ -225,7 +225,7 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId } catch (e: Exception) { getLogger().error( "Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " + - "$clientInstructionsPath: $e" + "$clientInstructionsPath: $e" ) } finally { runWriteAction { 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 99d59891d09..f21c3e7ccd8 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 @@ -5,9 +5,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog import com.intellij.testFramework.LightVirtualFile -import java.util.zip.ZipOutputStream -import java.util.zip.ZipEntry -import java.io.FileOutputStream import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue @@ -41,6 +38,9 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.downloadCli import software.aws.toolkits.jetbrains.services.codemodernizer.utils.filterOnlyParentFiles import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile import software.aws.toolkits.telemetry.CodeTransformPreValidationError +import java.io.FileOutputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream import kotlin.io.path.Path import kotlin.io.path.createTempDirectory import kotlin.io.path.exists diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index eebcef29f33..d4d13b0d418 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -8,7 +8,6 @@ import io.mockk.just import io.mockk.mockkStatic import io.mockk.runs import io.mockk.verify -import kotlin.io.path.createTempFile import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat import org.junit.Before @@ -40,6 +39,7 @@ import software.aws.toolkits.jetbrains.utils.rules.addFileToModule import software.aws.toolkits.resources.message import java.util.concurrent.atomic.AtomicBoolean import java.util.zip.ZipFile +import kotlin.io.path.createTempFile class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase() { @Before From 15270ec08c3f31406916beafe9b01f5e60db2fb9 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Mon, 28 Apr 2025 09:45:32 -0700 Subject: [PATCH 09/16] alphabetize messages --- .../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 6ded544b51d..3720c69650e 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -754,9 +754,9 @@ codemodernizer.migration_plan.header.awsq=
{0} lines of code were submitted for transformation. If you reach the quota for lines of code included in your subscription, you will be charged ${1} for each additional line of code. You might be charged up to ${2} for this transformation. To avoid being charged, stop the transformation job before it completes. For more information on pricing and quotas, see Amazon Q Developer pricing.

codemodernizer.migration_plan.header.description=Plan to transform your module codemodernizer.migration_plan.header.title=Code Transformation plan by Amazon Q +codemodernizer.migration_plan.substeps.description_completed=Build completed codemodernizer.migration_plan.substeps.description_failed=Build failed codemodernizer.migration_plan.substeps.description_stopped=Job is stopped -codemodernizer.migration_plan.substeps.description_completed=Build completed codemodernizer.migration_summary.header.title=Transformation summary codemodernizer.notification.info.download.started.content=Downloading the updated code codemodernizer.notification.info.download.started.title=Download Started From 6e71b8e281ce1c4ed268b24dfd9ea0b91cc48059 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Mon, 28 Apr 2025 16:28:58 -0700 Subject: [PATCH 10/16] fix detekt --- .../codemodernizer/constants/CodeTransformChatItems.kt | 2 +- .../controller/CodeTransformChatController.kt | 4 +--- .../codemodernizer/utils/CodeTransformFileUtils.kt | 8 +++++++- 3 files changed, 9 insertions(+), 5 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 5800c9ff5ad..dc983f6e6d7 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 @@ -458,7 +458,7 @@ fun buildSQLMetadataValidationErrorChatContent(errorReason: String) = CodeTransf fun buildCustomDependencyVersionsFileInvalidChatContent() = CodeTransformChatMessageContent( type = CodeTransformChatMessageType.FinalizedAnswer, - message = "The .yaml file you uploaded does not follow the format of the sample YAML file provided.", + message = "The file you uploaded does not follow the format of the sample YAML file provided.", ) fun buildUserCancelledChatContent() = CodeTransformChatMessageContent( 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 4ce408528c1..b7575464125 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 @@ -370,7 +370,6 @@ class CodeTransformChatController( withContext(EDT) { val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() .withDescription("Select metadata file") - .withExtensionFilter("zip") val selectedZipFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext val extractedZip = createTempDirectory("codeTransformSQLMetadata", null) @@ -452,9 +451,8 @@ class CodeTransformChatController( withContext(EDT) { val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() .withDescription("Select .yaml file") - .withExtensionFilter("yaml") val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext - val isValid = validateYamlFile(selectedFile.readText()) + val isValid = validateYamlFile(selectedFile) if (!isValid) { codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent()) codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt index 8ca05bf3946..2a7dff2aee0 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.application.runReadAction import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.readText import kotlinx.coroutines.withContext import software.aws.toolkits.core.utils.createParentDirectories import software.aws.toolkits.core.utils.createTemporaryZipFile @@ -195,7 +196,12 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo return report } -fun validateYamlFile(fileContents: String): Boolean { +fun validateYamlFile(file: VirtualFile): Boolean { + if (!file.name.lowercase().endsWith(".yaml")) { + getLogger().error { "Custom versions file is not a YAML file: ${file.name}"} + return false + } + val fileContents = file.readText() val requiredKeys = listOf("dependencyManagement:", "identifier:", "targetVersion:") for (key in requiredKeys) { if (!fileContents.contains(key)) { From a572783f97456e609b9dbf437ead91f12626589a Mon Sep 17 00:00:00 2001 From: David Hasani Date: Mon, 28 Apr 2025 16:43:23 -0700 Subject: [PATCH 11/16] add test --- .../controller/CodeTransformChatController.kt | 5 +-- .../utils/CodeTransformFileUtils.kt | 2 +- .../CodeWhispererCodeModernizerUtilsTest.kt | 39 +++++++++++++++---- 3 files changed, 35 insertions(+), 11 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 b7575464125..7e1f17ce257 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 @@ -12,7 +12,6 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.util.io.FileUtil.createTempDirectory import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.readText import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -119,8 +118,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTrans import software.aws.toolkits.jetbrains.services.codemodernizer.utils.toVirtualFile import software.aws.toolkits.jetbrains.services.codemodernizer.utils.tryGetJdk import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateCustomVersionsFile import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata -import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType @@ -452,7 +451,7 @@ class CodeTransformChatController( val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() .withDescription("Select .yaml file") val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext - val isValid = validateYamlFile(selectedFile) + val isValid = validateCustomVersionsFile(selectedFile) if (!isValid) { codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent()) codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup()) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt index 2a7dff2aee0..c160f157b5b 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt @@ -196,7 +196,7 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo return report } -fun validateYamlFile(file: VirtualFile): Boolean { +fun validateCustomVersionsFile(file: VirtualFile): Boolean { if (!file.name.lowercase().endsWith(".yaml")) { getLogger().error { "Custom versions file is not a YAML file: ${file.name}"} return false diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index d4d13b0d418..21bc2cf302d 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -3,6 +3,7 @@ package software.aws.toolkits.jetbrains.services.codemodernizer +import com.intellij.testFramework.LightVirtualFile import io.mockk.every import io.mockk.just import io.mockk.mockkStatic @@ -10,6 +11,7 @@ import io.mockk.runs import io.mockk.verify import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.yaml.YAMLFileType import org.junit.Before import org.junit.Test import org.mockito.Mockito @@ -33,7 +35,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildF import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata -import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateCustomVersionsFile import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.jetbrains.utils.rules.addFileToModule import software.aws.toolkits.resources.message @@ -326,7 +328,7 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase } @Test - fun `WHEN validateYamlFile on fully valid yaml file THEN passes validation`() { + fun `WHEN validateCustomVersionsFile on fully valid yaml file THEN passes validation`() { val sampleFileContents = """name: "custom-dependency-management" description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21" dependencyManagement: @@ -341,12 +343,13 @@ dependencyManagement: versionProperty: "plugin.version" """.trimIndent() - val isValidYaml = validateYamlFile(sampleFileContents) - assertThat(isValidYaml).isTrue() + val virtualFile = LightVirtualFile("test-valid.yaml", YAMLFileType.YML, sampleFileContents) + val isValidFile = validateCustomVersionsFile(virtualFile) + assertThat(isValidFile).isTrue() } @Test - fun `WHEN validateYamlFile on invalid yaml file THEN fails validation`() { + fun `WHEN validateCustomVersionsFile on invalid yaml file THEN fails validation`() { val sampleFileContents = """name: "custom-dependency-management" description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21" invalidKey: @@ -361,8 +364,30 @@ invalidKey: versionProperty: "plugin.version" """.trimIndent() - val isValidYaml = validateYamlFile(sampleFileContents) - assertThat(isValidYaml).isFalse() + val virtualFile = LightVirtualFile("test-invalid.yaml", YAMLFileType.YML, sampleFileContents) + val isValidFile = validateCustomVersionsFile(virtualFile) + assertThat(isValidFile).isFalse() + } + + @Test + fun `WHEN validateCustomVersionsFile on non-yaml file THEN fails validation`() { + val sampleFileContents = """name: "custom-dependency-management" +description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21" +dependencyManagement: + dependencies: + - identifier: "com.example:library1" + targetVersion: "2.1.0" + versionProperty: "library1.version" + originType: "FIRST_PARTY" + plugins: + - identifier: "com.example.plugin" + targetVersion: "1.2.0" + versionProperty: "plugin.version" + """.trimIndent() + + val virtualFile = LightVirtualFile("test-invalid-file-type.txt", sampleFileContents) + val isValidFile = validateCustomVersionsFile(virtualFile) + assertThat(isValidFile).isFalse() } @Test From efd0412c87d1458967580132ce2a03f770346369 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Mon, 28 Apr 2025 17:30:45 -0700 Subject: [PATCH 12/16] fix detekt again --- .../codemodernizer/CodeModernizerSession.kt | 2 +- .../utils/CodeTransformApiUtils.kt | 26 ++++++++++--------- .../utils/CodeTransformFileUtils.kt | 2 +- .../CodeWhispererCodeModernizerUtilsTest.kt | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) 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 b19bd8e1fcf..b1ff57d6c8d 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 @@ -338,7 +338,7 @@ class CodeModernizerSession( fun resumeTransformation() { val clientAdaptor = GumbyClient.getInstance(sessionContext.project) clientAdaptor.resumeCodeTransformation(state.currentJobId as JobId, TransformationUserActionStatus.COMPLETED) - getLogger().info("Successfully resumed transformation with status of COMPLETED") + getLogger().info { "Successfully resumed transformation with status of COMPLETED" } } fun rejectHilAndContinue(): ResumeTransformationResponse { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index 6c010c39af6..a3f97a4aec6 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -36,7 +36,9 @@ import software.amazon.awssdk.services.codewhispererruntime.model.ValidationExce import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException import software.aws.toolkits.core.utils.WaiterUnrecoverableException import software.aws.toolkits.core.utils.Waiters.waitUntil +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.jetbrains.core.coroutines.EDT import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager @@ -172,22 +174,22 @@ suspend fun JobId.pollTransformationStatusAndPlan( suspend fun attemptLocalBuild(plan: TransformationPlan, jobId: JobId, project: Project) { val artifactId = getClientInstructionArtifactId(plan) - getLogger().info("Found artifactId: $artifactId") + getLogger().info { "Found artifactId: $artifactId" } if (artifactId != null) { val clientInstructionsPath = downloadClientInstructions(jobId, artifactId, project) - getLogger().info("Downloaded client instructions for job ${jobId.id} and artifact $artifactId at: $clientInstructionsPath") + getLogger().info { "Downloaded client instructions for job ${jobId.id} and artifact $artifactId at: $clientInstructionsPath" } processClientInstructions(clientInstructionsPath, jobId, artifactId, project) - getLogger().info("Finished processing client instructions for job ${jobId.id} and artifact $artifactId") + getLogger().info { "Finished processing client instructions for job ${jobId.id} and artifact $artifactId" } } } suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId, artifactId: String, project: Project) { var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_$artifactId", null).toPath() - getLogger().info("About to copy the original project ZIP to: $copyOfProjectSources") + getLogger().info { "About to copy the original project ZIP to: $copyOfProjectSources" } val originalProjectZip = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.originalUploadZipPath originalProjectZip?.let { unzipFile(it, copyOfProjectSources, isSqlMetadata = false, extractOnlySources = true) } copyOfProjectSources = copyOfProjectSources.resolve("sources") // where the user's source code is within the upload ZIP - getLogger().info("Copied and unzipped original project sources to: $copyOfProjectSources") + getLogger().info { "Copied and unzipped original project sources to: $copyOfProjectSources" } val targetDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(copyOfProjectSources.toFile()) ?: throw RuntimeException("Cannot find copy of project sources directory") @@ -217,16 +219,16 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId null, null ).execute() - getLogger().info("Successfully applied patch file at $clientInstructionsPath") + getLogger().info { "Successfully applied patch file at $clientInstructionsPath" } val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(clientInstructionsPath.toFile()) ?: throw RuntimeException("Cannot find patch file at $clientInstructionsPath") FileEditorManager.getInstance(project).openFile(virtualFile, true) } catch (e: Exception) { - getLogger().error( + getLogger().error { "Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " + "$clientInstructionsPath: $e" - ) + } } finally { runWriteAction { ModuleManager.getInstance(project).disposeModule(tempModule) @@ -236,21 +238,21 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId } val (exitCode, buildOutput) = runClientSideBuild(targetDir, CodeModernizerManager.LOG, project) - getLogger().info("Ran client-side build with an exit code of $exitCode") + getLogger().info { "Ran client-side build with an exit code of $exitCode" } val uploadZip = createClientSideBuildUploadZip(exitCode, buildOutput) - getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}") + getLogger().info { "Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}" } val uploadContext = UploadContext.fromTransformationUploadContext( TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build() ) getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId") try { CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext) - getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now") + getLogger().info { "Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now" } CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation() } finally { uploadZip.deleteRecursively() copyOfProjectSources.toFile().deleteRecursively() - getLogger().info("Deleted copy of project sources and client-side build upload ZIP") + getLogger().info { "Deleted copy of project sources and client-side build upload ZIP" } } // switch back to Transformation Hub view runInEdt { diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt index c160f157b5b..ea19a954342 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt @@ -198,7 +198,7 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo fun validateCustomVersionsFile(file: VirtualFile): Boolean { if (!file.name.lowercase().endsWith(".yaml")) { - getLogger().error { "Custom versions file is not a YAML file: ${file.name}"} + getLogger().error { "Custom versions file is not a YAML file: ${file.name}" } return false } val fileContents = file.readText() diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt index 21bc2cf302d..37482669432 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt @@ -34,8 +34,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getTableMap import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildFile import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken -import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateCustomVersionsFile +import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata import software.aws.toolkits.jetbrains.utils.notifyStickyWarn import software.aws.toolkits.jetbrains.utils.rules.addFileToModule import software.aws.toolkits.resources.message From 7ebc0f8590468eb764b51552219f5a6a9162900e Mon Sep 17 00:00:00 2001 From: David Hasani Date: Tue, 29 Apr 2025 10:07:04 -0700 Subject: [PATCH 13/16] fix tests --- .../CodeWhispererCodeModernizerSessionTest.kt | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) 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 044cb72a757..72fef62a11e 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 @@ -26,6 +26,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.mockito.ArgumentMatchers.nullable import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import org.mockito.Mockito.spy @@ -45,6 +46,7 @@ import software.amazon.awssdk.awscore.util.AwsHeader import software.amazon.awssdk.http.SdkHttpResponse import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlResponse import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus +import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext import software.amazon.awssdk.services.ssooidc.model.SsoOidcException import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult @@ -410,12 +412,12 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa fun `CodeModernizer can create modernization job`() = runTest { doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) + doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) doNothing().whenever(clientAdaptorSpy).uploadArtifactToS3(any(), any(), any(), any(), any()) doReturn(exampleStartCodeMigrationResponse).whenever(clientAdaptorSpy).startCodeModernization(any(), any(), any()) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.Started(jobId)) - verify(clientAdaptorSpy, times(1)).createGumbyUploadUrl(any()) + verify(clientAdaptorSpy, times(1)).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) verify(clientAdaptorSpy, times(1)).startCodeModernization(any(), any(), any()) verify(clientAdaptorSpy, times(1)).uploadArtifactToS3(any(), any(), any(), any(), any()) verifyNoMoreInteractions(clientAdaptorSpy) @@ -425,7 +427,7 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa fun `CodeModernizer cannot upload payload due to already disposed`() = runTest { doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) + doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) doAnswer { throw AlreadyDisposedException("mock exception") }.whenever(clientAdaptorSpy).uploadArtifactToS3(any(), any(), any(), any(), any()) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.Disposed) @@ -436,7 +438,7 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa setupConnection(BearerTokenAuthState.AUTHORIZED) doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doAnswer { throw SsoOidcException.builder().build() }.whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) + doAnswer { throw SsoOidcException.builder().build() }.whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.CREDENTIALS_EXPIRED)) } @@ -454,8 +456,11 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa fun `CodeModernizer cannot upload payload due to presigned url issue`() = runTest { doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) - doAnswer { throw HttpRequests.HttpStatusException("mock error", 403, "mock url") }.whenever(testSessionSpy).uploadPayload(any()) + doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) + doAnswer { throw HttpRequests.HttpStatusException("mock error", 403, "mock url") }.whenever(testSessionSpy).uploadPayload( + any(), + nullable(UploadContext::class.java) + ) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.PRESIGNED_URL_EXPIRED)) verify(testSessionStateSpy, times(1)).putJobHistory(any(), eq(TransformationStatus.FAILED), any(), any()) @@ -466,8 +471,11 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa fun `CodeModernizer cannot upload payload due to other status code`() = runTest { doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) - doAnswer { throw HttpRequests.HttpStatusException("mock error", 407, "mock url") }.whenever(testSessionSpy).uploadPayload(any()) + doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) + doAnswer { throw HttpRequests.HttpStatusException("mock error", 407, "mock url") }.whenever(testSessionSpy).uploadPayload( + any(), + nullable(UploadContext::class.java) + ) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.HTTP_ERROR(407))) verify(testSessionStateSpy, times(1)).putJobHistory(any(), eq(TransformationStatus.FAILED), any(), any()) @@ -478,7 +486,7 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa fun `CodeModernizer cannot upload payload due to unknown client-side issue`() = runTest { doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) + doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) doAnswer { throw Exception("mock client-side exception") }.whenever(clientAdaptorSpy).uploadArtifactToS3(any(), any(), any(), any(), any()) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER("mock client-side exception"))) @@ -490,8 +498,8 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa fun `CodeModernizer cannot upload payload due to connection refused`() = runTest { doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt"))) .whenever(testSessionContextSpy).createZipWithModuleFiles(any()) - doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any()) - doAnswer { throw ConnectException("mock exception") }.whenever(testSessionSpy).uploadPayload(any()) + doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) + doAnswer { throw ConnectException("mock exception") }.whenever(testSessionSpy).uploadPayload(any(), nullable(UploadContext::class.java)) val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/"))) assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.CONNECTION_REFUSED)) verify(testSessionStateSpy, times(1)).putJobHistory(any(), eq(TransformationStatus.FAILED), any(), any()) @@ -558,14 +566,14 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa val expectedSha256checksum: String = Base64.getEncoder().encodeToString(DigestUtils.sha256(FileInputStream(expectedFilePath.toAbsolutePath().toString()))) clientAdaptorSpy.stub { - onGeneric { clientAdaptorSpy.createGumbyUploadUrl(any()) } + onGeneric { clientAdaptorSpy.createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) } .thenReturn(gumbyUploadUrlResponse) } wireMock.stubFor(put(urlEqualTo("/")).willReturn(aResponse().withStatus(200))) - testSessionSpy.uploadPayload(expectedFilePath.toFile()) + testSessionSpy.uploadPayload(expectedFilePath.toFile(), null) val inOrder = inOrder(clientAdaptorSpy) - inOrder.verify(clientAdaptorSpy).createGumbyUploadUrl(eq(expectedSha256checksum)) + inOrder.verify(clientAdaptorSpy).createGumbyUploadUrl(eq(expectedSha256checksum), nullable(UploadContext::class.java)) inOrder.verify(clientAdaptorSpy).uploadArtifactToS3( eq(gumbyUploadUrlResponse.uploadUrl()), eq(expectedFilePath.toFile()), From d986546d32eac5bc0379fffc2ccb824ffc8e872d Mon Sep 17 00:00:00 2001 From: David Hasani Date: Tue, 29 Apr 2025 12:15:05 -0700 Subject: [PATCH 14/16] fix tests again --- .../utils/CodeTransformApiUtils.kt | 2 +- .../CodeWhispererCodeModernizerTest.kt | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt index a3f97a4aec6..6495508328b 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt @@ -244,7 +244,7 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId val uploadContext = UploadContext.fromTransformationUploadContext( TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build() ) - getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId") + getLogger().info { "About to call uploadPayload for job ${jobId.id} and artifact $artifactId" } try { CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext) getLogger().info { "Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now" } 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 f21c3e7ccd8..c5927c6d733 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 @@ -38,6 +38,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.downloadCli import software.aws.toolkits.jetbrains.services.codemodernizer.utils.filterOnlyParentFiles import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile import software.aws.toolkits.telemetry.CodeTransformPreValidationError +import java.io.ByteArrayOutputStream import java.io.FileOutputStream import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream @@ -160,8 +161,15 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { DownloadArtifactResult.ParseZipFailure( ParseZipFailureReason(TransformationDownloadArtifactType.LOGS, "Could not find build log") ) - val mockDownloadResult = listOf() - doReturn(mockDownloadResult).whenever(clientAdaptorSpy) + val mockZipBytes = ByteArrayOutputStream().use { bos -> + ZipOutputStream(bos).use { zos -> + zos.putNextEntry(ZipEntry("some-other-file.txt")) + zos.write("mock content".toByteArray()) + zos.closeEntry() + } + bos.toByteArray() + } + doReturn(listOf(mockZipBytes)).whenever(clientAdaptorSpy) .downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS) val result = handler.downloadArtifact(jobId, TransformationDownloadArtifactType.LOGS, false) verify(clientAdaptorSpy, times(1)).downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS) @@ -172,10 +180,21 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() { fun `downloadClientInstructions downloads and extracts patch file`() = runBlocking { val jobId = JobId("test-job-id") val artifactId = "test-artifact-id" - val mockBytes = "mock content".toByteArray() - doReturn(mockBytes).whenever(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId) + val mockZipBytes = ByteArrayOutputStream().use { bos -> + ZipOutputStream(bos).use { zos -> + zos.putNextEntry(ZipEntry("diff.patch")) + zos.write("mock content".toByteArray()) + zos.closeEntry() + } + bos.toByteArray() + } + doReturn(listOf(mockZipBytes)).whenever(clientAdaptorSpy).downloadExportResultArchive( + jobId, + artifactId, + TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS + ) val result = downloadClientInstructions(jobId, artifactId, project) - verify(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId) + verify(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS) assertEquals(result.fileName.toString(), "diff.patch") } From 4fe84a66228f1790c0043e27a7fb0987304caae9 Mon Sep 17 00:00:00 2001 From: David Hasani Date: Thu, 1 May 2025 16:49:02 -0700 Subject: [PATCH 15/16] address comment --- .../codemodernizer/ideMaven/MavenRunnerUtils.kt | 2 +- .../codemodernizer/ideMaven/TransformRunnable.kt | 4 +++- .../ElasticGumbyClientMavenSupport-1.0.jar | Bin 0 -> 7657 bytes 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar 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 2168e00eb23..35ecb95564e 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 @@ -47,7 +47,7 @@ fun runClientSideBuild(targetDir: VirtualFile, logger: Logger, project: Project) FileEditorManager.getInstance(project).openFile(buildLogOutputVirtualFile, true) } } - return buildRunnable.exitCode to buildRunnable.getOutput().toString() + return buildRunnable.getExitCode() to buildRunnable.getOutput().toString() } fun runHilMavenCopyDependency( diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt index 7741306cb7c..cc5307b6062 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt @@ -4,13 +4,15 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven class TransformRunnable : Runnable { - var exitCode: Int? = null + private var exitCode: Int? = null private var output: String? = null fun setExitCode(i: Int) { exitCode = i } + fun getExitCode(): Int? = exitCode + override fun run() { // do nothing } diff --git a/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar b/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..de2cf80be8ab941f2793236db8caab1fb4288c1e GIT binary patch literal 7657 zcmb_>1yoyW);3nOP~2S$MT>ip00lyEm*P$cZp8@>#a)U!4N_c+mg4TN#VJ~#^oP}% zd*}9ke`jW`*;(i0&B}hBz0c0sZ<75e%E2Sx!oVOS!!*jIYs1_d+{5YKQ0@;PKvj(8 zrGgY2JdEOB9IJfb4oU7Ei0+Sj_@9nIF@={>02NhMpwuaFpkH2&g>@8Nj)iGxV7OYD zeS&jkb8Qpu7qWZ&A5jtR*Tx{*zXkkPAB=za7}^?ofb0xi9e?Znkmdv9pWdc6hK^2_ z#^%npM()3bQvV)mY-4F^=k!~Kr~eUyt)Yvl-QReolI6qp?mvyZM=&rp{{@et1IWtM z*a>K8XK7~Y=p+HMvAKT?OaV}YuS3l23AkB^Lidlh#+lkz?j z>e6c|(f#BL+m3aN%)5loPgaPu-F6IMhswxuULXij=1r#Wd2I`FnqSQBwPnH8M})iQ zy>)pD9t~oaSf*cI)BmKl*i_rf2-o@c`%5Ov3iiChumrn}kps%3HB4QIb~Xt)==eta zB+K|!pb*dVqB`Qed3{XTcM;PoI^ypAF&`{=8)CV!(jJjPOm=s6*`$gzt+-pMjmYdm zch6<&Qcq)IxXF{lLTuiCEY`U+N_eNZl)IBAQ*xb7=R5zZRC=XZL6Isi7y*Q*! z!Waw-In?s8^qy@4TXRR}@@=h<5cG1?RNnA#NhlOqdFiC0Lp~Niks~;oVPeoruTn!S zSqLeqbmLqaY1(k)>wJH^XHgh1x=Inuu$HnqDx7nqOBQ>yAFwj_5h?LoNVrnODEg$+ z#EO$z62@z{y4$;iAw1CmBfi=(Whov>K#zkkZs|ObqcWanL2)$Mu&gY%v5trrKxsWs zz8vl@SI)jsV}AG=F>9Sso$xtYBNL%Vzj7!YF%?$1wyNi*z=~mz^w=Dkd5?`uPOZ|N z0F6w``4t4|((bESu-MSfA|p|khz$l|grepzRvdWKL zvuOEH0g>BHzHn$-dLSuSnjs12&yt-bn4x|5F*@eu+jlkjpa&H#Qv+`#`ay+bYqNX_R@G%S=WzdV(Z^a-DK}#o`8@W-rnf zoW(o&0oexMT+o(TMGnPnwdVARvh|lS8ooPih-7rz6d-5Vpg)#xRrKRAMIXluPgP&V z51h|UXLIr6$FXIOl7pX*j)nV#HaBE`z)FB%|GKf2tL(?u-Zx#n(qoxmdbF4eqVbyK#57o33< z4oPUJi0_ki;gjG{@X!YbYaE>1m(`r+TWKjEv!O3HS)e7@`iNORapYdiQA_}u#I(Tj z2BiC-3S3yvDxdXkGqxt*Cx|M22zSi_pz|1velS8P0CxppV=*>0JzPbTz z25lSYg+%u>@yW<8=Zpdn%fSZB{`QYuzjpR(9s4KLVD zyDulW@cUj^?r4lm4a$lsYE(QYA7{^wSj?JqBwQo30k;3gPr-%BO_u&#!YZcNG3OJ78%hhPEvYzJ9O-zu*={!1=b*>fa>DpTnEkK=!TDQ`h#<094iejTDnkmD`i$m==(fBB;u+hBfa5<>98M`OmgumQRwPz%=M}5(GS%1aR=ipWu5_NR&|AE$P_MZW-ClZ0-$$EQ z>+B=yu+`jp~&sS7M^xFda*pO=N^A9mf9Ir|jh(rW(j%^3#}ON~n6TyZInn zSe%)T%z}7I%z}e9iST}7`s1@H&?hNihG&=+`b5GeXCzp5K*=2SDNCmA#{(0J1;+Rt zaGX+XXb3F51B6i-SjoI$je}_n!TiakhM7@vN<*AIAgqz=2%9GNE~UBsB-~SH=5}#d z16km3->Cv&@zSTL0Ob{W^zcWCk>lJ4yX#iFjJ#wCnkB2x$&zwqvsvsIXr#vK2Nj6w z%xKIyK8;niG;Dm#jdAOEt`gPTPZLeVC_uGWGZTss>{4(ZVqBn$gNW?{s(eYeMPR|U z%`8i-W(^c$E{r9w#w>v^$GlX+qN z4XUEO=i%2`nO}?gB&D4%L%;=((42q>PcaCqUBO-YVrS-AXYIn25yQB8$9|1tO8u<9UxiODsor&BCBCv6MXr16qfOTMs!`m~6uo6cnxRO{G7MEru% z&`~G#zRVw%T*f zF*Fd&ZWz^-)uGBQHp0}cL{_)zvelwbgm9^FJ|$0BFo`1EpsGuEGo&j3bTW^}cHMQu zS&|RH91JaM0Fb+xp68hW;tq8X@PSrUm{F^&WUl?UdIi48yHF3ufpe3JRq{2hvEG+s z<{MQpP8~uW6m*?2Ce&5D8T!r{8IRZWrwF>@7lDr?_@e6e+>j2}^JGcY{rf7w;?epM zZ{jwtSjmnOEoB|{pJVfL2Hu?bLN0f&ByLAd{2R>=%#z$WO-$!)3%OHVq7>d%xKA$y z2Xm#5oUkut4PP_%M|CYeCL|gP)Q--u)! z6kN>(jpK1Q1fuGSl&F(v8Rmb*T2gxAh>qmQ;*`4WgE19Zxy* z{)muhjyHr&k(yUvb6u(PJ*ELIdr#S>RytYRhC_VAM!&!v_VDNsDFJOvatuGST$f<@ zi#$RL{j6Jpu2U}wzJ-~X=~L@wbcdXAmBY&B6V_p=<=5|o)Mv%7K`5%YTEo>h3MZR- znJq)>p2T-jz00y(2i|(|1<|J38ec!*_7}N~$Z8HLxnD2uU9}2n+ks7qYw1ELl;3>G zgxJhQ=m@LpKI(>eC%Gbv_J~?sg+}?r2YFCQMVpav^54FWyNp=y-fj6rd>v;Jv-^Ql zIm9RN=yMi|O%^s!L0}du`VZ=n)0<*`2{){^w*t4N?Ts460XHJou4F&_e&8kx>%uG2 z=4#;az|~F?^nIsEBPzNh`H{Qo<9v(V#&pras=&bRc(r5W$YYlG$Se|7JADo3+w}81 z{nzQ_we9to)`wQMZ4IWtb1j%T;lar748@;T!qkJ=&`7&4fgMkEb^FXuF7jw^|lXUZN zw*bo38M&zbqZVh_g8c&urM#wm4Uh8|FPnr8r(fxw*lh5RH`?}e1HP=T<;qx)*Xq-< zqA`vl96nX;!zZ1w^Qjr;rg zBI0jwD&1wZKV03tbsq~*O|zx3JX#JfnV^iu)I3F9Qwtr zG!096UeDo{U>kb`#?Ch`7&mt{H%F9|kdf@dORbM(a{}X0pwi$&mA_vYj&nxbq}Wzd zInz8RXOcHxl1lobPBWRoUah7yFOn|zDsx>5>rfz-C)`Gq-TnIk)Pe&$RH2_E&ENlA zO3`$^M-~fLV;uQgO&R^tizgnM%Ii{5!aGGL9*|8h<;sPzg?xJ6Dr|>EeMT(pS%dZ! z?Wvlt0i9O~z-BRWH7V`Z7{_U>$)$zkZ8-k66f6ZW(NaSKh6?ASo1OQzR8T!hZme-Y z(+rjUET4|#WJ0!5WM*@dY+O+8wt>$!@Xe^OgTq`OsXipAMiwcHFh_+z%}6U{hUNX4 z5nar{Q`_SB6s6_R4LQ)NNj@o16El?yYVdkC-liy&gfO0A`SZZ0U5~Ozye!P!U@z!c z2f4XS3gu2OiV68672It?2Icg3D_Tox(mpMpLCX*Z+LYuiJ2OFztC`(H#8m>=JJfff z*>cR}>#*KKEsBCL2aLMZn5CYm)sGZbn)X$Z(?8~1q%uHhn{8m8nG|}%oJ-VW6B1Pt zb&#O;?m^yrn+S!VOIWay8t?{|2dy7S%qa045_TMld+SNeXz;ZfBJ)OT`53Rx5Q^6k zXLUtLWyQ9-!c6rgC5ej32|@ER$7z;ltf?(X{UgJ( zp6}tFH>3;+#PQ29|QTeg(owCGRn#eryfN$91Y@^at-$XIa%ABq$`+%8FPt!xD zMnJ`4CRSF#_L3!Dy+owplNsG5jj+wsHl7_y}ReAAdo$r-D|W{r48K~n5$3oHl8O5|tnHC8-0bOzpKdWN(#7?Hn<`;Zb8 zyG&VNsMrZbdpdoL0xpJg<44DqXhK`V4hR(U|Avi)2Tis2r;m{p($3=j80s;N5ZQ`q za5c^)k=xecgU^k3*G!jKWOv00&-b0Z!wOT)cApmG?T%yYQ$;Mk@O(T!p;4j9^N@m4 zv3O5Wwo5C#)P>T>{Yliz&thd4%r%XUJE{dfi3OqoVvK8AJ9r`vYqQpqa|UkKcXN(U z6Jn8=Zk1}k(t+p{88qM==rBvmNxB-avV>nm!0K4!m3IyDc-RZFkkbtrcR2`FtZmNw zX6UwL=3-pGCa4^@JNt@Z!q3pGx`k zDlKY8c&CGL>N65s0`9zUVouDozY{`_@pD$nyLR-tb{4yKz}Ktf0>}DB+qRMm^P!`z zn7NnW-lmz>G{QGeI6Oo-u3ckR%0?I4AgKEcYRpqHYc zlM)qodJ{k66+!r&cJwPF2SGH>t3pXS5f(X{HwxA+amUO3i#=6u?@okEh?E#w8ed9`M*PHT{l zrwW3OvH5ndJQb$&!ti83tG5T)-4E6sS>0@HOk0MG7NoE$Z4X*M_e-KRQcv2{bpEdr=)&EDiDDpfKJ-r}}iL2DhwQHQb-aY$je&+F< zX*a3I5bSPP+VT2~oEUc75~*w>mcQkkk2$OvUjK4&LUaR3Q4SUk7ykb*w%pg^-Y{Vf z#2%jiDC4iNU!|7^=LgI4W4u5A0s9vr=2wOX?|-U14|>Z_dkE}uzkJY2eusEaUw+yH zBK3axS9Rrg*at1;FK*`8Bg&N85j926sQ~{`d9!$Myc(%>Fj${xy+br-pwf z!jAl(C-V0h;;(Uj9mf3`N9n8b6e4d}l|AD^0lz-VW73CfwKKP^GKP>M1+xkJIh53JipaX>f literal 0 HcmV?d00001 From 2e42f245ea4160487eb9c7d60003993e7e6d8bae Mon Sep 17 00:00:00 2001 From: David Hasani Date: Thu, 1 May 2025 16:50:43 -0700 Subject: [PATCH 16/16] remove jar --- .../ElasticGumbyClientMavenSupport-1.0.jar | Bin 7657 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar diff --git a/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar b/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar deleted file mode 100644 index de2cf80be8ab941f2793236db8caab1fb4288c1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7657 zcmb_>1yoyW);3nOP~2S$MT>ip00lyEm*P$cZp8@>#a)U!4N_c+mg4TN#VJ~#^oP}% zd*}9ke`jW`*;(i0&B}hBz0c0sZ<75e%E2Sx!oVOS!!*jIYs1_d+{5YKQ0@;PKvj(8 zrGgY2JdEOB9IJfb4oU7Ei0+Sj_@9nIF@={>02NhMpwuaFpkH2&g>@8Nj)iGxV7OYD zeS&jkb8Qpu7qWZ&A5jtR*Tx{*zXkkPAB=za7}^?ofb0xi9e?Znkmdv9pWdc6hK^2_ z#^%npM()3bQvV)mY-4F^=k!~Kr~eUyt)Yvl-QReolI6qp?mvyZM=&rp{{@et1IWtM z*a>K8XK7~Y=p+HMvAKT?OaV}YuS3l23AkB^Lidlh#+lkz?j z>e6c|(f#BL+m3aN%)5loPgaPu-F6IMhswxuULXij=1r#Wd2I`FnqSQBwPnH8M})iQ zy>)pD9t~oaSf*cI)BmKl*i_rf2-o@c`%5Ov3iiChumrn}kps%3HB4QIb~Xt)==eta zB+K|!pb*dVqB`Qed3{XTcM;PoI^ypAF&`{=8)CV!(jJjPOm=s6*`$gzt+-pMjmYdm zch6<&Qcq)IxXF{lLTuiCEY`U+N_eNZl)IBAQ*xb7=R5zZRC=XZL6Isi7y*Q*! z!Waw-In?s8^qy@4TXRR}@@=h<5cG1?RNnA#NhlOqdFiC0Lp~Niks~;oVPeoruTn!S zSqLeqbmLqaY1(k)>wJH^XHgh1x=Inuu$HnqDx7nqOBQ>yAFwj_5h?LoNVrnODEg$+ z#EO$z62@z{y4$;iAw1CmBfi=(Whov>K#zkkZs|ObqcWanL2)$Mu&gY%v5trrKxsWs zz8vl@SI)jsV}AG=F>9Sso$xtYBNL%Vzj7!YF%?$1wyNi*z=~mz^w=Dkd5?`uPOZ|N z0F6w``4t4|((bESu-MSfA|p|khz$l|grepzRvdWKL zvuOEH0g>BHzHn$-dLSuSnjs12&yt-bn4x|5F*@eu+jlkjpa&H#Qv+`#`ay+bYqNX_R@G%S=WzdV(Z^a-DK}#o`8@W-rnf zoW(o&0oexMT+o(TMGnPnwdVARvh|lS8ooPih-7rz6d-5Vpg)#xRrKRAMIXluPgP&V z51h|UXLIr6$FXIOl7pX*j)nV#HaBE`z)FB%|GKf2tL(?u-Zx#n(qoxmdbF4eqVbyK#57o33< z4oPUJi0_ki;gjG{@X!YbYaE>1m(`r+TWKjEv!O3HS)e7@`iNORapYdiQA_}u#I(Tj z2BiC-3S3yvDxdXkGqxt*Cx|M22zSi_pz|1velS8P0CxppV=*>0JzPbTz z25lSYg+%u>@yW<8=Zpdn%fSZB{`QYuzjpR(9s4KLVD zyDulW@cUj^?r4lm4a$lsYE(QYA7{^wSj?JqBwQo30k;3gPr-%BO_u&#!YZcNG3OJ78%hhPEvYzJ9O-zu*={!1=b*>fa>DpTnEkK=!TDQ`h#<094iejTDnkmD`i$m==(fBB;u+hBfa5<>98M`OmgumQRwPz%=M}5(GS%1aR=ipWu5_NR&|AE$P_MZW-ClZ0-$$EQ z>+B=yu+`jp~&sS7M^xFda*pO=N^A9mf9Ir|jh(rW(j%^3#}ON~n6TyZInn zSe%)T%z}7I%z}e9iST}7`s1@H&?hNihG&=+`b5GeXCzp5K*=2SDNCmA#{(0J1;+Rt zaGX+XXb3F51B6i-SjoI$je}_n!TiakhM7@vN<*AIAgqz=2%9GNE~UBsB-~SH=5}#d z16km3->Cv&@zSTL0Ob{W^zcWCk>lJ4yX#iFjJ#wCnkB2x$&zwqvsvsIXr#vK2Nj6w z%xKIyK8;niG;Dm#jdAOEt`gPTPZLeVC_uGWGZTss>{4(ZVqBn$gNW?{s(eYeMPR|U z%`8i-W(^c$E{r9w#w>v^$GlX+qN z4XUEO=i%2`nO}?gB&D4%L%;=((42q>PcaCqUBO-YVrS-AXYIn25yQB8$9|1tO8u<9UxiODsor&BCBCv6MXr16qfOTMs!`m~6uo6cnxRO{G7MEru% z&`~G#zRVw%T*f zF*Fd&ZWz^-)uGBQHp0}cL{_)zvelwbgm9^FJ|$0BFo`1EpsGuEGo&j3bTW^}cHMQu zS&|RH91JaM0Fb+xp68hW;tq8X@PSrUm{F^&WUl?UdIi48yHF3ufpe3JRq{2hvEG+s z<{MQpP8~uW6m*?2Ce&5D8T!r{8IRZWrwF>@7lDr?_@e6e+>j2}^JGcY{rf7w;?epM zZ{jwtSjmnOEoB|{pJVfL2Hu?bLN0f&ByLAd{2R>=%#z$WO-$!)3%OHVq7>d%xKA$y z2Xm#5oUkut4PP_%M|CYeCL|gP)Q--u)! z6kN>(jpK1Q1fuGSl&F(v8Rmb*T2gxAh>qmQ;*`4WgE19Zxy* z{)muhjyHr&k(yUvb6u(PJ*ELIdr#S>RytYRhC_VAM!&!v_VDNsDFJOvatuGST$f<@ zi#$RL{j6Jpu2U}wzJ-~X=~L@wbcdXAmBY&B6V_p=<=5|o)Mv%7K`5%YTEo>h3MZR- znJq)>p2T-jz00y(2i|(|1<|J38ec!*_7}N~$Z8HLxnD2uU9}2n+ks7qYw1ELl;3>G zgxJhQ=m@LpKI(>eC%Gbv_J~?sg+}?r2YFCQMVpav^54FWyNp=y-fj6rd>v;Jv-^Ql zIm9RN=yMi|O%^s!L0}du`VZ=n)0<*`2{){^w*t4N?Ts460XHJou4F&_e&8kx>%uG2 z=4#;az|~F?^nIsEBPzNh`H{Qo<9v(V#&pras=&bRc(r5W$YYlG$Se|7JADo3+w}81 z{nzQ_we9to)`wQMZ4IWtb1j%T;lar748@;T!qkJ=&`7&4fgMkEb^FXuF7jw^|lXUZN zw*bo38M&zbqZVh_g8c&urM#wm4Uh8|FPnr8r(fxw*lh5RH`?}e1HP=T<;qx)*Xq-< zqA`vl96nX;!zZ1w^Qjr;rg zBI0jwD&1wZKV03tbsq~*O|zx3JX#JfnV^iu)I3F9Qwtr zG!096UeDo{U>kb`#?Ch`7&mt{H%F9|kdf@dORbM(a{}X0pwi$&mA_vYj&nxbq}Wzd zInz8RXOcHxl1lobPBWRoUah7yFOn|zDsx>5>rfz-C)`Gq-TnIk)Pe&$RH2_E&ENlA zO3`$^M-~fLV;uQgO&R^tizgnM%Ii{5!aGGL9*|8h<;sPzg?xJ6Dr|>EeMT(pS%dZ! z?Wvlt0i9O~z-BRWH7V`Z7{_U>$)$zkZ8-k66f6ZW(NaSKh6?ASo1OQzR8T!hZme-Y z(+rjUET4|#WJ0!5WM*@dY+O+8wt>$!@Xe^OgTq`OsXipAMiwcHFh_+z%}6U{hUNX4 z5nar{Q`_SB6s6_R4LQ)NNj@o16El?yYVdkC-liy&gfO0A`SZZ0U5~Ozye!P!U@z!c z2f4XS3gu2OiV68672It?2Icg3D_Tox(mpMpLCX*Z+LYuiJ2OFztC`(H#8m>=JJfff z*>cR}>#*KKEsBCL2aLMZn5CYm)sGZbn)X$Z(?8~1q%uHhn{8m8nG|}%oJ-VW6B1Pt zb&#O;?m^yrn+S!VOIWay8t?{|2dy7S%qa045_TMld+SNeXz;ZfBJ)OT`53Rx5Q^6k zXLUtLWyQ9-!c6rgC5ej32|@ER$7z;ltf?(X{UgJ( zp6}tFH>3;+#PQ29|QTeg(owCGRn#eryfN$91Y@^at-$XIa%ABq$`+%8FPt!xD zMnJ`4CRSF#_L3!Dy+owplNsG5jj+wsHl7_y}ReAAdo$r-D|W{r48K~n5$3oHl8O5|tnHC8-0bOzpKdWN(#7?Hn<`;Zb8 zyG&VNsMrZbdpdoL0xpJg<44DqXhK`V4hR(U|Avi)2Tis2r;m{p($3=j80s;N5ZQ`q za5c^)k=xecgU^k3*G!jKWOv00&-b0Z!wOT)cApmG?T%yYQ$;Mk@O(T!p;4j9^N@m4 zv3O5Wwo5C#)P>T>{Yliz&thd4%r%XUJE{dfi3OqoVvK8AJ9r`vYqQpqa|UkKcXN(U z6Jn8=Zk1}k(t+p{88qM==rBvmNxB-avV>nm!0K4!m3IyDc-RZFkkbtrcR2`FtZmNw zX6UwL=3-pGCa4^@JNt@Z!q3pGx`k zDlKY8c&CGL>N65s0`9zUVouDozY{`_@pD$nyLR-tb{4yKz}Ktf0>}DB+qRMm^P!`z zn7NnW-lmz>G{QGeI6Oo-u3ckR%0?I4AgKEcYRpqHYc zlM)qodJ{k66+!r&cJwPF2SGH>t3pXS5f(X{HwxA+amUO3i#=6u?@okEh?E#w8ed9`M*PHT{l zrwW3OvH5ndJQb$&!ti83tG5T)-4E6sS>0@HOk0MG7NoE$Z4X*M_e-KRQcv2{bpEdr=)&EDiDDpfKJ-r}}iL2DhwQHQb-aY$je&+F< zX*a3I5bSPP+VT2~oEUc75~*w>mcQkkk2$OvUjK4&LUaR3Q4SUk7ykb*w%pg^-Y{Vf z#2%jiDC4iNU!|7^=LgI4W4u5A0s9vr=2wOX?|-U14|>Z_dkE}uzkJY2eusEaUw+yH zBK3axS9Rrg*at1;FK*`8Bg&N85j926sQ~{`d9!$Myc(%>Fj${xy+br-pwf z!jAl(C-V0h;;(Uj9mf3`N9n8b6e4d}l|AD^0lz-VW73CfwKKP^GKP>M1+xkJIh53JipaX>f