Skip to content

Commit 79ac5cb

Browse files
authored
feat(amazonq): plan explainability support (#4358)
1 parent 6dc48f6 commit 79ac5cb

32 files changed

+875
-262
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Amazon Q Code Transformation: include details about expected changes in transformation plan"
4+
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ package software.aws.toolkits.jetbrains.services.codemodernizer
55

66
import com.intellij.openapi.application.runInEdt
77
import com.intellij.openapi.application.runReadAction
8+
import com.intellij.openapi.fileEditor.FileEditorManager
89
import com.intellij.openapi.project.Project
910
import com.intellij.openapi.vcs.changes.ChangeListManager
1011
import com.intellij.openapi.vcs.changes.patch.ApplyPatchDefaultExecutor
1112
import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog
1213
import com.intellij.openapi.vcs.changes.patch.ApplyPatchMode
1314
import com.intellij.openapi.vcs.changes.patch.ImportToShelfExecutor
15+
import com.intellij.openapi.vfs.LocalFileSystem
1416
import com.intellij.openapi.vfs.VirtualFile
1517
import kotlinx.coroutines.launch
1618
import software.aws.toolkits.core.utils.error
@@ -21,7 +23,6 @@ import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
2123
import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
2224
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact
2325
import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
24-
import software.aws.toolkits.jetbrains.services.codemodernizer.summary.CodeModernizerSummaryEditorProvider
2526
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.TROUBLESHOOTING_URL_DOWNLOAD_DIFF
2627
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction
2728
import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
@@ -190,8 +191,13 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
190191
runReadAction {
191192
projectCoroutineScope(project).launch {
192193
val result = downloadArtifact(job)
193-
val summary = result.artifact?.summary ?: return@launch notifyUnableToShowSummary()
194-
runInEdt { CodeModernizerSummaryEditorProvider.openEditor(project, summary) }
194+
val summary = result.artifact?.summaryMarkdownFile ?: return@launch notifyUnableToShowSummary()
195+
val summaryMarkdownVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(summary)
196+
if (summaryMarkdownVirtualFile != null) {
197+
runInEdt {
198+
FileEditorManager.getInstance(project).openFile(summaryMarkdownVirtualFile, true)
199+
}
200+
}
195201
}
196202
}
197203
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const val ZIP_SOURCES_PATH = "sources"
4747
const val BUILD_LOG_PATH = "build-logs.txt"
4848
const val UPLOAD_ZIP_MANIFEST_VERSION = 1.0F
4949
const val MAX_ZIP_SIZE = 1000000000 // 1GB
50+
const val EXPLAINABILITY_V1 = "EXPLAINABILITY_V1"
5051

5152
class CodeModernizerSession(
5253
val sessionContext: CodeModernizerSessionContext,

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

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
package software.aws.toolkits.jetbrains.services.codemodernizer.constants
55

6-
import com.intellij.openapi.projectRoots.JavaSdkVersion
76
import com.intellij.ui.JBColor
7+
import com.intellij.util.ui.JBFont
88
import icons.AwsIcons
99
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererColorUtil
1010
import java.awt.Color
11+
import java.awt.Font
1112
import java.awt.GridBagConstraints
13+
import java.awt.Insets
1214
import javax.swing.BorderFactory
1315

1416
const val FEATURE_NAME = "Amazon Q Transform"
@@ -37,28 +39,41 @@ class CodeModernizerUIConstants {
3739
const val PLAN_PADDING_RIGHT = 50
3840

3941
const val TITLE_FONT_SIZE = 24f
40-
const val TRANSFORMATION_STEP_TITLE_FONT_SIZE = 14f
41-
const val STEP_FONT_SIZE = 14f
42+
const val SUBTITLE_FONT_SIZE = 18f
43+
const val STEP_NAME_FONT_SIZE = 16f
44+
const val STEP_INFO_FONT_SIZE = 14f
45+
const val TABLE_NAME_FONT_SIZE = 14f
46+
const val STEP_DESCRIPTION_FONT_SIZE = 14 // needs to be an integer
4247

4348
const val NAME_PADDING_TOP = 10
4449
const val NAME_PADDING_LEFT = 10
4550
const val NAME_PADDING_BOTTOM = 10
4651
const val NAME_PADDING_RIGHT = 10
4752

48-
const val DESCRP_PADDING_TOP = 0
49-
const val DESCRP_PADDING_LEFT = 10
50-
const val DESCRP_PADDING_BOTTOM = 10
51-
const val DESCRP_PADDING_RIGHT = 10
53+
const val DESCRIPTION_PADDING_TOP = 0
54+
const val DESCRIPTION_PADDING_LEFT = 10
55+
const val DESCRIPTION_PADDING_BOTTOM = 25
56+
const val DESCRIPTION_PADDING_RIGHT = 10
57+
58+
const val TABLE_PADDING_TOP = 10
59+
const val TABLE_PADDING_LEFT = 10
60+
const val TABLE_PADDING_RIGHT = 10
61+
62+
const val TABLE_NAME_PADDING_TOP = 0
63+
const val TABLE_NAME_PADDING_LEFT = 10
64+
const val TABLE_NAME_PADDING_BOTTOM = 0
65+
const val TABLE_NAME_PADDING_RIGHT = 0
66+
67+
const val TABLE_ROW_HEIGHT = 25
5268
}
5369

5470
object FONT_CONSTRAINTS {
71+
const val PLAIN = 0
5572
const val BOLD = 1
5673
const val ITALIC = 2
5774
}
5875

5976
companion object {
60-
val supportedSourceJDKs = listOf(JavaSdkVersion.JDK_1_8, JavaSdkVersion.JDK_11)
61-
const val SINGLE_SPACE_STRING: String = " "
6277
const val EMPTY_SPACE_STRING: String = ""
6378
val transformationPlanPlaneConstraint = GridBagConstraints().apply {
6479
gridx = 0
@@ -67,13 +82,54 @@ class CodeModernizerUIConstants {
6782
fill = GridBagConstraints.HORIZONTAL
6883
anchor = GridBagConstraints.NORTH
6984
}
85+
86+
val transformationPlanAppendixConstraint = GridBagConstraints().apply {
87+
gridx = 0
88+
gridy = GridBagConstraints.RELATIVE
89+
fill = GridBagConstraints.HORIZONTAL
90+
anchor = GridBagConstraints.NORTHWEST
91+
weightx = 1.0
92+
insets = Insets(5, 5, 5, 5)
93+
}
94+
95+
val DESCRIPTION_FONT = JBFont.create(Font("Arial", Font.PLAIN, PLAN_CONSTRAINTS.STEP_DESCRIPTION_FONT_SIZE))
96+
97+
val PLAN_BORDER = BorderFactory.createEmptyBorder(
98+
PLAN_CONSTRAINTS.PLAN_PADDING_TOP,
99+
PLAN_CONSTRAINTS.PLAN_PADDING_LEFT,
100+
PLAN_CONSTRAINTS.PLAN_PADDING_BOTTOM,
101+
PLAN_CONSTRAINTS.PLAN_PADDING_RIGHT
102+
)
103+
104+
val NAME_BORDER = BorderFactory.createEmptyBorder(
105+
PLAN_CONSTRAINTS.NAME_PADDING_TOP,
106+
PLAN_CONSTRAINTS.NAME_PADDING_LEFT,
107+
PLAN_CONSTRAINTS.NAME_PADDING_BOTTOM,
108+
PLAN_CONSTRAINTS.NAME_PADDING_RIGHT
109+
)
110+
111+
val DESCRIPTION_BORDER = BorderFactory.createEmptyBorder(
112+
PLAN_CONSTRAINTS.DESCRIPTION_PADDING_TOP,
113+
PLAN_CONSTRAINTS.DESCRIPTION_PADDING_LEFT,
114+
PLAN_CONSTRAINTS.DESCRIPTION_PADDING_BOTTOM,
115+
PLAN_CONSTRAINTS.DESCRIPTION_PADDING_RIGHT
116+
)
117+
118+
val TABLE_NAME_BORDER = BorderFactory.createEmptyBorder(
119+
PLAN_CONSTRAINTS.TABLE_NAME_PADDING_TOP,
120+
PLAN_CONSTRAINTS.TABLE_NAME_PADDING_LEFT,
121+
PLAN_CONSTRAINTS.TABLE_NAME_PADDING_BOTTOM,
122+
PLAN_CONSTRAINTS.TABLE_NAME_PADDING_RIGHT
123+
)
124+
70125
val TRANSFORMATION_PLAN_PANEL_BORDER = BorderFactory.createCompoundBorder(
71126
BorderFactory.createEmptyBorder(10, 10, 10, 10),
72127
BorderFactory.createLineBorder(CodeWhispererColorUtil.POPUP_BUTTON_BORDER, 1, true)
73128

74129
)
75-
val STEP_INTRO_BORDER = BorderFactory.createEmptyBorder(10, 10, 10, 10)
76-
val STEP_INTRO_TITLE_BORDER = BorderFactory.createEmptyBorder(0, 0, 5, 0)
130+
val APPENDIX_BORDER = BorderFactory.createEmptyBorder(10, 10, 10, 10)
131+
val STEPS_INTRO_BORDER = BorderFactory.createEmptyBorder(10, 10, 30, 10)
132+
val STEPS_INTRO_TITLE_BORDER = BorderFactory.createEmptyBorder(0, 0, 5, 0)
77133
val TRANSFORMATION_STEP_PANEL_COMPOUND_BORDER = BorderFactory.createCompoundBorder(
78134
BorderFactory.createCompoundBorder(
79135
BorderFactory.createEmptyBorder(0, 20, 20, 20),
@@ -88,14 +144,14 @@ class CodeModernizerUIConstants {
88144
),
89145
BorderFactory.createEmptyBorder(10, 10, 10, 10)
90146
)
91-
val TRANSFORMATION_STEPS_INFO_AWSQ_BORDER = BorderFactory.createCompoundBorder(
147+
val TRANSFORMATION_STEPS_QCT_INFO_BORDER = BorderFactory.createCompoundBorder(
92148
BorderFactory.createCompoundBorder(
93149
BorderFactory.createEmptyBorder(0, 0, 0, 10),
94150
BorderFactory.createLineBorder(Color.GRAY, 1, true)
95151
),
96152
BorderFactory.createEmptyBorder(10, 10, 10, 10)
97153
)
98-
val TRANSOFORMATION_PLAN_INFO_BORDER = BorderFactory.createEmptyBorder(10, 10, 10, 10)
154+
val TRANSFORMATION_PLAN_INFO_BORDER = BorderFactory.createEmptyBorder(10, 10, 10, 10)
99155
val FILLER_CONSTRAINT = GridBagConstraints().apply {
100156
gridy = 1
101157
weighty = 1.0

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ fun getTransformationProgressStepsByTransformationStepId(
1818
transformationPlan: TransformationPlan?
1919
): BuildProgressTimelineStepDetailsList<BuildProgressTimelineStepDetailItem> {
2020
val stepList = BuildProgressTimelineStepDetailsList<BuildProgressTimelineStepDetailItem>()
21-
val transformationStep = transformationPlan?.transformationSteps()?.get(stepId - 1)
21+
// skip step 0 (contains supplemental info)
22+
val transformationStep = transformationPlan?.transformationSteps()?.drop(1)?.get(stepId - 1)
2223
transformationStep?.progressUpdates()?.let { progressUpdates ->
2324
for (progressStep in progressUpdates) {
2425
if (progressStep != null) {

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import software.aws.toolkits.core.utils.getLogger
1414
import software.aws.toolkits.core.utils.warn
1515
import software.aws.toolkits.jetbrains.services.codemodernizer.TransformationSummary
1616
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
17+
import java.io.File
1718
import kotlin.io.path.ExperimentalPathApi
1819
import kotlin.io.path.Path
1920
import kotlin.io.path.isDirectory
@@ -26,7 +27,8 @@ open class CodeModernizerArtifact(
2627
val zipPath: String,
2728
val manifest: CodeModernizerManifest,
2829
private val patches: List<VirtualFile>,
29-
val summary: TransformationSummary
30+
val summary: TransformationSummary,
31+
val summaryMarkdownFile: File,
3032
) {
3133
val patch: VirtualFile
3234
get() = patches.first()
@@ -57,8 +59,9 @@ open class CodeModernizerArtifact(
5759
}
5860
val patches = extractPatches(manifest)
5961
val summary = extractSummary(manifest)
62+
val summaryMarkdownFile = getSummaryFile(manifest)
6063
if (patches.size != 1) throw RuntimeException("Expected 1 patch, but found ${patches.size}")
61-
return CodeModernizerArtifact(zipPath, manifest, patches, summary)
64+
return CodeModernizerArtifact(zipPath, manifest, patches, summary, summaryMarkdownFile)
6265
}
6366
throw RuntimeException("Could not find artifact")
6467
}
@@ -71,18 +74,21 @@ open class CodeModernizerArtifact(
7174
return TransformationSummary(summaryFile.readText())
7275
}
7376

77+
private fun getSummaryFile(manifest: CodeModernizerManifest) = tempDir.toPath().resolve(manifest.summaryRoot).resolve(summaryNameInZip).toFile()
78+
7479
/**
7580
* Attempts to load the manifest from the zip file. Throws an exception if the manifest is not found or cannot be serialized.
7681
*/
7782
private fun loadManifest(): CodeModernizerManifest {
78-
val manifestFile = tempDir.listFiles()
79-
?.firstOrNull { Path(it.name).endsWith(manifestPathInZip) }
80-
?: throw RuntimeException("Could not find manifest")
83+
val manifestFile =
84+
tempDir.listFiles()
85+
?.firstOrNull { it.name.endsWith(manifestPathInZip) }
86+
?: throw RuntimeException("Could not find manifest")
8187
try {
8288
val manifest = MAPPER.readValue(manifestFile, CodeModernizerManifest::class.java)
83-
if (manifest.version == 0.0F || manifest.patchesRoot == null || manifest.summaryRoot == null) {
89+
if (manifest.version == 0.0F) {
8490
throw RuntimeException(
85-
"Unable to deserialize the manifest"
91+
"Unable to deserialize the manifest",
8692
)
8793
}
8894
return manifest
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.codemodernizer.model
5+
6+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
7+
import com.fasterxml.jackson.annotation.JsonProperty
8+
9+
@JsonIgnoreProperties(ignoreUnknown = true)
10+
data class PlanTable(
11+
@JsonProperty("columnNames")
12+
val columns: List<String>,
13+
@JsonProperty("rows")
14+
val rows: List<PlanTableRow>,
15+
@JsonProperty("name")
16+
val name: String,
17+
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.codemodernizer.model
5+
6+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
7+
import com.fasterxml.jackson.annotation.JsonProperty
8+
9+
@JsonIgnoreProperties(ignoreUnknown = true)
10+
data class PlanTableRow(
11+
@JsonProperty("name")
12+
val name: String?,
13+
@JsonProperty("value")
14+
val value: String?,
15+
@JsonProperty("dependencyName")
16+
val dependency: String?,
17+
@JsonProperty("action")
18+
val action: String?,
19+
@JsonProperty("currentVersion")
20+
val currentVersion: String?,
21+
@JsonProperty("targetVersion")
22+
val targetVersion: String?,
23+
@JsonProperty("apiFullyQualifiedName")
24+
val deprecatedCode: String?,
25+
@JsonProperty("numChangedFiles")
26+
val filesToBeChanged: String?,
27+
@JsonProperty("relativePath")
28+
val filePath: String?,
29+
) {
30+
fun getValueForColumn(col: String): String? =
31+
when (col) {
32+
"name" -> name
33+
"value" -> value
34+
"dependencyName" -> dependency
35+
"action" -> action
36+
"currentVersion" -> currentVersion
37+
"targetVersion" -> targetVersion
38+
"apiFullyQualifiedName" -> deprecatedCode
39+
"numChangedFiles" -> filesToBeChanged
40+
"relativePath" -> filePath
41+
else -> "-"
42+
}
43+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
package software.aws.toolkits.jetbrains.services.codemodernizer.model
55

66
import software.aws.toolkits.jetbrains.services.codemodernizer.BUILD_LOG_PATH
7+
import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1
78
import software.aws.toolkits.jetbrains.services.codemodernizer.UPLOAD_ZIP_MANIFEST_VERSION
89
import software.aws.toolkits.jetbrains.services.codemodernizer.ZIP_SOURCES_PATH
910

1011
data class ZipManifest(
1112
val sourcesRoot: String = ZIP_SOURCES_PATH,
1213
val dependenciesRoot: String? = null,
1314
val buildLogs: String = BUILD_LOG_PATH,
14-
val version: String = UPLOAD_ZIP_MANIFEST_VERSION.toString()
15+
val version: String = UPLOAD_ZIP_MANIFEST_VERSION.toString(),
16+
val transformCapabilities: List<String> = listOf(EXPLAINABILITY_V1)
1517
)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ class BuildProgressStepDetailsPanel : JPanel(BorderLayout()) {
168168
model.addElement(element)
169169
}
170170
stepDetailsList.model = model
171-
val stepName = transformationPlanLocal?.transformationSteps()?.get(currentStepIdRendered - 1)?.name().orEmpty()
171+
// skip step 0 (contains supplemental info)
172+
val stepName = transformationPlanLocal?.transformationSteps()?.drop(1)?.get(currentStepIdRendered - 1)?.name().orEmpty()
172173
setHeaderText("$stepName details")
173174
revalidate()
174175
repaint()

0 commit comments

Comments
 (0)