diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index df1b811eb5..984706e427 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ mockito = "5.10.0" mockitoKotlin = "5.2.1" mockk = "1.13.8" node-gradle = "7.0.1" -telemetryGenerator = "1.0.197" +telemetryGenerator = "1.0.201" testLogger = "4.0.0" testRetry = "1.5.2" # test-only; platform provides slf4j transitively at runtime. <233, 1.7.36; >=233, 2.0.9 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 29afb72012..dfb3ff9800 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 @@ -137,7 +137,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G ) dialog.isModal = true - telemetry.vcsDiffViewerVisible(jobId) + telemetry.vcsDiffViewerVisible(jobId) // download succeeded if (dialog.showAndGet()) { telemetry.vcsViewerSubmitted(jobId) } else { 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 c8896f2562..a5c7e51005 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 @@ -143,19 +143,13 @@ class CodeModernizerSession( LOG.warn { "Job was cancelled by user before start job was called" } CodeModernizerStartJobResult.Cancelled } else { - val errorMessage = "Failed to start job" - LOG.error(e) { errorMessage } state.putJobHistory(sessionContext, TransformationStatus.FAILED) state.currentJobStatus = TransformationStatus.FAILED - telemetry.error(errorMessage) CodeModernizerStartJobResult.UnableToStartJob(e.message.toString()) } } catch (e: Exception) { - val errorMessage = "Failed to start job" - LOG.error(e) { errorMessage } state.putJobHistory(sessionContext, TransformationStatus.FAILED) state.currentJobStatus = TransformationStatus.FAILED - telemetry.error(errorMessage) CodeModernizerStartJobResult.UnableToStartJob(e.message.toString()) } finally { deleteUploadArtifact(payload) @@ -273,6 +267,8 @@ class CodeModernizerSession( ) { shouldStop.get() } } catch (e: Exception) { val errorMessage = "Unexpected error when uploading artifact to S3: ${e.localizedMessage}" + LOG.error { errorMessage } + // emit this metric here manually since we don't use callApi(), which emits its own metric telemetry.apiError(errorMessage, CodeTransformApiNames.UploadZip, createUploadUrlResponse.uploadId()) throw e // pass along error to callee } diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformTelemetryManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformTelemetryManager.kt index ff4f7b86c3..a6d50ebbe1 100644 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformTelemetryManager.kt +++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformTelemetryManager.kt @@ -8,6 +8,10 @@ import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import org.apache.commons.codec.digest.DigestUtils import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus +import software.aws.toolkits.jetbrains.core.gettingstarted.editor.ActiveConnection +import software.aws.toolkits.jetbrains.core.gettingstarted.editor.ActiveConnectionType +import software.aws.toolkits.jetbrains.core.gettingstarted.editor.BearerTokenFeatureSet +import software.aws.toolkits.jetbrains.core.gettingstarted.editor.checkBearerConnectionValidity import software.aws.toolkits.jetbrains.services.codemodernizer.model.CustomerSelection import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId import software.aws.toolkits.jetbrains.services.codemodernizer.model.ValidationResult @@ -20,9 +24,9 @@ import software.aws.toolkits.telemetry.CodeTransformJavaTargetVersionsAllowed import software.aws.toolkits.telemetry.CodeTransformMavenBuildCommand import software.aws.toolkits.telemetry.CodeTransformPatchViewerCancelSrcComponents import software.aws.toolkits.telemetry.CodeTransformPreValidationError -import software.aws.toolkits.telemetry.CodeTransformStartSrcComponents import software.aws.toolkits.telemetry.CodeTransformVCSViewerSrcComponents import software.aws.toolkits.telemetry.CodetransformTelemetry +import software.aws.toolkits.telemetry.CredentialSourceId import software.aws.toolkits.telemetry.Result import java.time.Instant import java.util.Base64 @@ -34,14 +38,6 @@ import java.util.Base64 class CodeTransformTelemetryManager(private val project: Project) { private val sessionId get() = CodeTransformTelemetryState.instance.getSessionId() private val currentJobStatus get() = CodeModernizerSessionState.getInstance(project).currentJobStatus.toString() - fun sendUserClickedTelemetry(srcStartComponent: CodeTransformStartSrcComponents) { - CodeTransformTelemetryState.instance.setStartTime() - CodeTransformTelemetryState.instance.setSessionId() - CodetransformTelemetry.isDoubleClickedToTriggerUserModal( - codeTransformStartSrcComponents = srcStartComponent, - codeTransformSessionId = sessionId, - ) - } private fun getProjectHash(customerSelection: CustomerSelection) = Base64.getEncoder().encodeToString( DigestUtils.sha256(customerSelection.configurationFile.toNioPath().toAbsolutePath().toString()) @@ -183,10 +179,16 @@ class CodeTransformTelemetryManager(private val project: Project) { } fun dependenciesCopied() = CodetransformTelemetry.dependenciesCopied(codeTransformSessionId = sessionId) - fun configurationFileSelectedChanged() = CodetransformTelemetry.configurationFileSelectedChanged(codeTransformSessionId = sessionId) - fun jobIsStartedFromUserPopupClick() = CodetransformTelemetry.jobIsStartedFromUserPopupClick(codeTransformSessionId = sessionId) - fun jobIsCanceledFromUserPopupClick() = CodetransformTelemetry.jobIsCanceledFromUserPopupClick(codeTransformSessionId = sessionId) - fun jobIsStartedFromChatPrompt() = CodetransformTelemetry.jobIsStartedFromChatPrompt(codeTransformSessionId = sessionId) + fun jobIsStartedFromChatPrompt() { + val connection = checkBearerConnectionValidity(project, BearerTokenFeatureSet.Q) + var authType: CredentialSourceId? = null + if (connection.connectionType == ActiveConnectionType.IAM_IDC && connection is ActiveConnection.ValidBearer) { + authType = CredentialSourceId.IamIdentityCenter + } else if (connection.connectionType == ActiveConnectionType.BUILDER_ID && connection is ActiveConnection.ValidBearer) { + authType = CredentialSourceId.AwsId + } + CodetransformTelemetry.jobIsStartedFromChatPrompt(codeTransformSessionId = sessionId, credentialSourceId = authType) + } companion object { fun getInstance(project: Project): CodeTransformTelemetryManager = project.service() 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 da9c3c0d8d..867f974605 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 @@ -54,7 +54,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.toVirtualFile import software.aws.toolkits.jetbrains.services.codemodernizer.tryGetJdk import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType import software.aws.toolkits.resources.message -import software.aws.toolkits.telemetry.CodeTransformStartSrcComponents class CodeTransformChatController( private val context: AmazonQAppInitContext, @@ -62,7 +61,6 @@ class CodeTransformChatController( ) : InboundAppMessagesHandler { private val authController = AuthController() private val messagePublisher = context.messagesFromAppToUi - private val telemetry = CodeTransformTelemetryManager.getInstance(context.project) private val codeModernizerManager = CodeModernizerManager.getInstance(context.project) private val codeTransformChatHelper = CodeTransformChatHelper(context.messagesFromAppToUi, chatSessionStorage) private val artifactHandler = ArtifactHandler(context.project, GumbyClient.getInstance(context.project)) @@ -72,9 +70,6 @@ class CodeTransformChatController( return } - CodeTransformTelemetryManager.getInstance(context.project).jobIsStartedFromChatPrompt() - - telemetry.sendUserClickedTelemetry(CodeTransformStartSrcComponents.ChatPrompt) codeTransformChatHelper.setActiveCodeTransformTabId(message.tabId) if (!message.startNewTransform) { @@ -108,6 +103,8 @@ class CodeTransformChatController( delay(500) + CodeTransformTelemetryManager.getInstance(context.project).jobIsStartedFromChatPrompt() + codeTransformChatHelper.addNewMessage( buildUserInputChatContent(context.project, validationResult) ) diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ui/components/PreCodeTransformUserDialog.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ui/components/PreCodeTransformUserDialog.kt deleted file mode 100644 index 169fe4658c..0000000000 --- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ui/components/PreCodeTransformUserDialog.kt +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package software.aws.toolkits.jetbrains.services.codemodernizer.ui.components - -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleUtil -import com.intellij.openapi.observable.util.whenItemSelected -import com.intellij.openapi.project.Project -import com.intellij.openapi.projectRoots.JavaSdkVersion -import com.intellij.openapi.ui.ComboBox -import com.intellij.openapi.ui.DialogBuilder -import com.intellij.openapi.ui.DialogPanel -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.ui.dsl.builder.AlignX -import com.intellij.ui.dsl.builder.COLUMNS_MEDIUM -import com.intellij.ui.dsl.builder.TopGap -import com.intellij.ui.dsl.builder.columns -import com.intellij.ui.dsl.builder.panel -import com.intellij.ui.dsl.builder.toMutableProperty -import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager -import software.aws.toolkits.jetbrains.services.codemodernizer.getSupportedJavaMappings -import software.aws.toolkits.jetbrains.services.codemodernizer.model.CustomerSelection -import software.aws.toolkits.jetbrains.services.codemodernizer.tryGetJdk -import software.aws.toolkits.resources.message -import kotlin.math.max - -class PreCodeTransformUserDialog( - val project: Project, - val supportedBuildFilesInProject: List, - val supportedJavaMappings: Map>, -) { - - internal data class Model( - var focusedBuildFileIndex: Int, - var focusedBuildFile: VirtualFile?, - var selectedMigrationPath: String?, - var supportedMigrationPaths: List, - var focusedBuildFileModule: Module?, - ) - - /** - * Opens a dialog to user allowing them to select a migration path and details about their project / module. - */ - fun create(): CustomerSelection? { - lateinit var dialogPanel: DialogPanel - lateinit var buildFileComboBox: ComboBox - - val telemetry = CodeTransformTelemetryManager.getInstance(project) - val buildfiles = supportedBuildFilesInProject - var focusedModuleIndex = 0 - var chosenBuildFile = buildfiles.firstOrNull() - val chosenFile = FileEditorManager.getInstance(project).selectedEditor?.file - - // Detect default selection for the build file - if (chosenFile != null) { - val focusedModule = ModuleUtil.findModuleForFile(chosenFile, project) - val matchingBuildFileForChosenModule = buildfiles.find { ModuleUtil.findModuleForFile(it, project) == focusedModule } - - if (focusedModule != null && matchingBuildFileForChosenModule != null) { - chosenBuildFile = matchingBuildFileForChosenModule - focusedModuleIndex = max(0, buildfiles.indexOfFirst { it == chosenBuildFile }) - } - } - - // Detect module for default selected file (if applicable) - var chosenModule: Module? = null - if (chosenBuildFile != null) { - chosenModule = ModuleUtil.findModuleForFile(chosenBuildFile, project) - } - - // Detect the supported migration path for the module, revert to project default if file not part of module. - fun supportedJdkForModuleOrProject(module: Module?): List { - val jdk = if (module != null) { - getSupportedJavaVersions(module) - } else { - project.getSupportedJavaMappings(supportedJavaMappings) - } - return jdk.map { it.replace("_", " ") } - } - - val supportedJavaVersions = supportedJdkForModuleOrProject(chosenModule) - - // Initialize model to hold form data - val model = Model( - focusedBuildFileIndex = focusedModuleIndex, - focusedBuildFile = chosenBuildFile, - focusedBuildFileModule = chosenModule, - selectedMigrationPath = supportedJavaVersions.firstOrNull(), - supportedMigrationPaths = supportedJavaVersions, - ) - - dialogPanel = panel { - row { text(message("codemodernizer.customerselectiondialog.description.main")) } - row { text(message("codemodernizer.customerselectiondialog.description.select")) } - row { - buildFileComboBox = comboBox(buildfiles.map { it.path }) - .bind({ it.selectedIndex }, { t, v -> t.selectedIndex = v }, model::focusedBuildFileIndex.toMutableProperty()) - .align(AlignX.FILL) - .columns(COLUMNS_MEDIUM) - .component - buildFileComboBox.whenItemSelected { - dialogPanel.apply() // apply user changes to model - model.focusedBuildFile = buildfiles[model.focusedBuildFileIndex] - model.focusedBuildFileModule = ModuleUtil.findModuleForFile(buildfiles[model.focusedBuildFileIndex], project) - model.supportedMigrationPaths = supportedJdkForModuleOrProject(model.focusedBuildFileModule) - dialogPanel.reset() // present model changes to user - } - buildFileComboBox.addActionListener { - telemetry.configurationFileSelectedChanged() - } - } - row { - this.topGap(TopGap.SMALL) - text(message("codemodernizer.customerselectiondialog.description.after_module")) - } - row { - text(message("codemodernizer.customerselectiondialog.description.after_module_part2")) - } - } - - val builder = DialogBuilder() - builder.setOkOperation { - telemetry.jobIsStartedFromUserPopupClick() - builder.dialogWrapper.close(DialogWrapper.OK_EXIT_CODE) - } - builder.addOkAction().setText(message("codemodernizer.customerselectiondialog.ok_button")) - builder.setCancelOperation { - telemetry.jobIsCanceledFromUserPopupClick() - builder.dialogWrapper.close(DialogWrapper.CANCEL_EXIT_CODE) - } - builder.addCancelAction() - builder.setCenterPanel(dialogPanel) - builder.setTitle(message("codemodernizer.customerselectiondialog.title")) - if (builder.showAndGet()) { - val selectedMigrationPath = model.selectedMigrationPath?.replace(" ", "_") ?: throw RuntimeException("Migration path is required") - val sourceJavaVersion = model.focusedBuildFileModule?.tryGetJdk(project) ?: project.tryGetJdk() - ?: throw RuntimeException("Unable to detect source language of selected ") - val targetJavaVersion = JavaSdkVersion.fromVersionString(selectedMigrationPath) ?: throw RuntimeException("Invalid migration path") - return CustomerSelection( - model.focusedBuildFile ?: throw RuntimeException("A build file must be selected"), - sourceJavaVersion, - targetJavaVersion, - ) - } - return null - } - - private fun getSupportedJavaVersions(module: Module?): List = - supportedJavaMappings.get(module?.tryGetJdk(project))?.map { it.name } ?: listOf("Unsupported module") -}