Skip to content

Commit 9a7052f

Browse files
Merge branch 'main' into samgst/bump-to-release-252
2 parents ca2dbe5 + a8dadbb commit 9a7052f

File tree

16 files changed

+204
-76
lines changed

16 files changed

+204
-76
lines changed

.changes/3.89.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"date" : "2025-08-07",
3+
"version" : "3.89",
4+
"entries" : [ {
5+
"type" : "bugfix",
6+
"description" : "/transform: validate YAML dependency file for required fields"
7+
} ]
8+
}

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# _3.89_ (2025-08-07)
2+
- **(Bug Fix)** /transform: validate YAML dependency file for required fields
3+
14
# _3.88_ (2025-08-04)
25
- **(Feature)** Add support for 2025.2
36
- **(Bug Fix)** Fix unsupported files being shown in file picker when selecting images for adding image context in Windows

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# Toolkit Version
5-
toolkitVersion=3.89-SNAPSHOT
5+
toolkitVersion=3.90-SNAPSHOT
66

77
# Publish Settings
88
publishToken=

plugins/amazonq/chat/jetbrains-community/resources/META-INF/plugin-chat.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<action id="aws.toolkit.open.q.window" class="software.aws.toolkits.jetbrains.services.amazonq.QRefreshPanelAction"/>
3434
<group id="aws.q.toolwindow.titleBar" popup="false" compact="true">
3535
<reference id="aws.toolkit.open.q.window"/>
36+
<action class="software.aws.toolkits.jetbrains.services.amazonq.GetAmazonQLogsAction" id="q.getLogs"/>
3637
</group>
3738
<!-- TODO: q.openchat will eventually be in amazonq, aws.toolkit.q.sign.in will eventually be in core. -->
3839
<action id="q.openchat" class="software.aws.toolkits.jetbrains.services.amazonq.QOpenPanelAction"/>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq
5+
6+
import com.intellij.icons.AllIcons
7+
import com.intellij.ide.actions.RevealFileAction
8+
import com.intellij.ide.logsUploader.LogPacker
9+
import com.intellij.openapi.actionSystem.ActionUpdateThread
10+
import com.intellij.openapi.actionSystem.AnActionEvent
11+
import com.intellij.openapi.project.DumbAwareAction
12+
import com.intellij.openapi.project.Project
13+
import com.intellij.openapi.ui.Messages
14+
import com.intellij.openapi.util.IconLoader
15+
import com.intellij.ui.ColorUtil
16+
import com.intellij.ui.JBColor
17+
import com.intellij.util.IconUtil
18+
import com.intellij.util.ui.UIUtil
19+
import kotlinx.coroutines.runBlocking
20+
import software.aws.toolkits.jetbrains.utils.notifyInfo
21+
import software.aws.toolkits.jetbrains.utils.runUnderProgressIfNeeded
22+
import software.aws.toolkits.resources.AmazonQBundle.message
23+
import software.aws.toolkits.resources.AwsCoreBundle
24+
25+
class GetAmazonQLogsAction : DumbAwareAction(message("amazonq.getLogs.tooltip.text")) {
26+
private val baseIcon = IconLoader.getIcon("/icons/file.svg", GetAmazonQLogsAction::class.java)
27+
28+
private val lightIcon by lazy {
29+
IconUtil.colorize(baseIcon, ColorUtil.brighter(UIUtil.getLabelForeground(), 2))
30+
}
31+
32+
override fun update(e: AnActionEvent) {
33+
e.presentation.icon = if (!JBColor.isBright()) {
34+
baseIcon
35+
} else {
36+
lightIcon
37+
}
38+
}
39+
40+
override fun getActionUpdateThread() = ActionUpdateThread.BGT
41+
override fun actionPerformed(e: AnActionEvent) {
42+
val project = e.project ?: return
43+
showLogCollectionWarningGetLogs(project)
44+
}
45+
46+
companion object {
47+
fun showLogCollectionWarningGetLogs(project: Project) {
48+
if (Messages.showOkCancelDialog(
49+
message("amazonq.logs.warning"),
50+
message("amazonq.getLogs"),
51+
AwsCoreBundle.message("general.ok"),
52+
AwsCoreBundle.message("general.cancel"),
53+
AllIcons.General.Warning
54+
) == 0
55+
) {
56+
runUnderProgressIfNeeded(project, message("amazonq.getLogs"), cancelable = true) {
57+
runBlocking {
58+
try {
59+
RevealFileAction.openFile(LogPacker.packLogs(project))
60+
} catch (_: Exception) {
61+
notifyInfo(message("amazonq.getLogs"), message("amazonq.logs.error"), project)
62+
}
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import software.aws.toolkits.core.utils.error
3333
import software.aws.toolkits.core.utils.getLogger
3434
import software.aws.toolkits.core.utils.info
3535
import software.aws.toolkits.core.utils.warn
36+
import software.aws.toolkits.jetbrains.services.amazonq.GetAmazonQLogsAction
3637
import software.aws.toolkits.jetbrains.services.amazonq.apps.AppConnection
3738
import software.aws.toolkits.jetbrains.services.amazonq.commands.MessageSerializer
3839
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQChatServer
@@ -419,33 +420,40 @@ class BrowserConnector(
419420
}
420421

421422
CHAT_TAB_BAR_ACTIONS -> {
422-
handleChat(AmazonQChatServer.tabBarActions, node) { params, invoke ->
423-
invoke()
424-
.whenComplete { actions, error ->
425-
try {
426-
if (error != null) {
427-
throw error
428-
}
429-
430-
browser.postChat(
431-
FlareUiMessage(
432-
command = CHAT_TAB_BAR_ACTIONS,
433-
params = actions
423+
val action = node.params.get("action")
424+
if (action.textValue() == "show_logs") {
425+
runInEdt {
426+
GetAmazonQLogsAction.showLogCollectionWarningGetLogs(project)
427+
}
428+
} else {
429+
handleChat(AmazonQChatServer.tabBarActions, node) { params, invoke ->
430+
invoke()
431+
.whenComplete { actions, error ->
432+
try {
433+
if (error != null) {
434+
throw error
435+
}
436+
437+
browser.postChat(
438+
FlareUiMessage(
439+
command = CHAT_TAB_BAR_ACTIONS,
440+
params = actions
441+
)
434442
)
435-
)
436-
} catch (e: Exception) {
437-
val cause = if (e is CompletionException) e.cause else e
438-
439-
// dont post error to UI if user cancels export
440-
if (cause is ResponseErrorException && cause.responseError.code == ResponseErrorCode.RequestCancelled.getValue()) {
441-
return@whenComplete
442-
}
443-
LOG.error { "Failed to perform chat tab bar action $e" }
444-
params.tabId?.let {
445-
browser.postChat(chatCommunicationManager.getErrorUiMessage(it, e, null))
443+
} catch (e: Exception) {
444+
val cause = if (e is CompletionException) e.cause else e
445+
446+
// dont post error to UI if user cancels export
447+
if (cause is ResponseErrorException && cause.responseError.code == ResponseErrorCode.RequestCancelled.getValue()) {
448+
return@whenComplete
449+
}
450+
LOG.error { "Failed to perform chat tab bar action $e" }
451+
params.tabId?.let {
452+
browser.postChat(chatCommunicationManager.getErrorUiMessage(it, e, null))
453+
}
446454
}
447455
}
448-
}
456+
}
449457
}
450458
}
451459

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,9 +419,9 @@ fun buildSQLMetadataValidationErrorChatContent(errorReason: String) = CodeTransf
419419
message = errorReason,
420420
)
421421

422-
fun buildCustomDependencyVersionsFileInvalidChatContent() = CodeTransformChatMessageContent(
422+
fun buildCustomDependencyVersionsFileInvalidChatContent(missingKey: String) = CodeTransformChatMessageContent(
423423
type = CodeTransformChatMessageType.FinalizedAnswer,
424-
message = message("codemodernizer.chat.message.custom_dependency_upgrades_invalid"),
424+
message = message("codemodernizer.chat.message.custom_dependency_upgrades_invalid", missingKey),
425425
)
426426

427427
fun buildUserCancelledChatContent() = CodeTransformChatMessageContent(

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,9 @@ class CodeTransformChatController(
432432
val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
433433
.withDescription("Select .yaml file")
434434
val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
435-
val isValid = validateCustomVersionsFile(selectedFile)
436-
if (!isValid) {
437-
codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent())
435+
val missingKey = validateCustomVersionsFile(selectedFile)
436+
if (missingKey != null) {
437+
codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent(missingKey))
438438
codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
439439
return@withContext
440440
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,21 +196,22 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo
196196
return report
197197
}
198198

199-
fun validateCustomVersionsFile(file: VirtualFile): Boolean {
199+
// return the first missing key in the custom versions file, or null if all required keys are present
200+
fun validateCustomVersionsFile(file: VirtualFile): String? {
200201
val validFileEndings = listOf("yaml", "yml")
201202
if (!validFileEndings.any { file.name.lowercase().endsWith(it) }) {
202203
getLogger<CodeTransformChatController>().error { "Custom versions file is not a YAML file: ${file.name}" }
203-
return false
204+
return message("codemodernizer.chat.message.custom_dependency_upgrades_invalid_not_yaml")
204205
}
205206
val fileContents = file.readText()
206-
val requiredKeys = listOf("dependencyManagement:", "identifier:", "targetVersion:")
207+
val requiredKeys = listOf("dependencyManagement", "identifier", "targetVersion", "originType")
207208
for (key in requiredKeys) {
208209
if (!fileContents.contains(key)) {
209210
getLogger<CodeTransformChatController>().error { "Missing yaml key: $key" }
210-
return false
211+
return key
211212
}
212213
}
213-
return true
214+
return null
214215
}
215216

216217
fun validateSctMetadata(sctFile: File?): SqlMetadataValidationResult {

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ dependencyManagement:
411411
""".trimIndent()
412412

413413
val virtualFile = LightVirtualFile("test-valid.yaml", YAMLFileType.YML, sampleFileContents)
414-
val isValidFile = validateCustomVersionsFile(virtualFile)
415-
assertThat(isValidFile).isTrue()
414+
val missingKey = validateCustomVersionsFile(virtualFile)
415+
assertThat(missingKey).isNull()
416416
}
417417

418418
@Test
@@ -432,8 +432,8 @@ invalidKey:
432432
""".trimIndent()
433433

434434
val virtualFile = LightVirtualFile("test-invalid.yaml", YAMLFileType.YML, sampleFileContents)
435-
val isValidFile = validateCustomVersionsFile(virtualFile)
436-
assertThat(isValidFile).isFalse()
435+
val missingKey = validateCustomVersionsFile(virtualFile)
436+
assertThat(missingKey).isEqualTo("dependencyManagement")
437437
}
438438

439439
@Test
@@ -454,7 +454,27 @@ dependencyManagement:
454454

455455
val virtualFile = LightVirtualFile("test-invalid-file-type.txt", sampleFileContents)
456456
val isValidFile = validateCustomVersionsFile(virtualFile)
457-
assertThat(isValidFile).isFalse()
457+
assertThat(isValidFile).isEqualTo(message("codemodernizer.chat.message.custom_dependency_upgrades_invalid_not_yaml"))
458+
}
459+
460+
@Test
461+
fun `WHEN validateCustomVersionsFile on yaml file missing originType THEN fails validation`() {
462+
val sampleFileContents = """name: "dependency-upgrade"
463+
description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
464+
dependencyManagement:
465+
dependencies:
466+
- identifier: "com.example:library1"
467+
targetVersion: "2.1.0"
468+
versionProperty: "library1.version"
469+
plugins:
470+
- identifier: "com.example:plugin"
471+
targetVersion: "1.2.0"
472+
versionProperty: "plugin.version"
473+
""".trimIndent()
474+
475+
val virtualFile = LightVirtualFile("sample.yaml", sampleFileContents)
476+
val missingKey = validateCustomVersionsFile(virtualFile)
477+
assertThat(missingKey).isEqualTo("originType")
458478
}
459479

460480
@Test

0 commit comments

Comments
 (0)