Skip to content

Commit fe316fa

Browse files
Merge main into feature/remote-chat
2 parents 4f9d2c3 + 4685aa0 commit fe316fa

File tree

7 files changed

+121
-23
lines changed

7 files changed

+121
-23
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.STATES_AFTE
5151
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.calculateTotalLatency
5252
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getModuleOrProjectNameForFile
5353
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilDependencyReportDir
54+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isPlanComplete
5455
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection
5556
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
5657
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.toTransformationLanguage
@@ -477,10 +478,12 @@ class CodeModernizerSession(
477478
}
478479
}
479480

480-
// Open the transformation plan detail panel once transformation plan is available (no plan for SQL conversions)
481-
if (transformType != CodeTransformType.SQL_CONVERSION && state.transformationPlan != null && !isTransformationPlanEditorOpened) {
482-
tryOpenTransformationPlanEditor()
483-
isTransformationPlanEditorOpened = true
481+
if (!isTransformationPlanEditorOpened && transformType == CodeTransformType.LANGUAGE_UPGRADE) {
482+
val isPlanComplete = isPlanComplete(state.transformationPlan)
483+
if (isPlanComplete) {
484+
tryOpenTransformationPlanEditor()
485+
isTransformationPlanEditorOpened = true
486+
}
484487
}
485488
val instant = Instant.now()
486489
// Set the job start time

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ data class PlanTable(
1111
@JsonProperty("columnNames")
1212
val columns: List<String>,
1313
@JsonProperty("rows")
14-
val rows: List<PlanTableRow>,
14+
val rows: MutableList<PlanTableRow>,
1515
@JsonProperty("name")
1616
val name: String,
1717
)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ data class ZipManifest(
1111
val version: String = UPLOAD_ZIP_MANIFEST_VERSION,
1212
val hilCapabilities: List<String> = listOf(HIL_1P_UPGRADE_CAPABILITY),
1313
// TODO: add CLIENT_SIDE_BUILD to transformCapabilities when releasing CSB
14+
// TODO: add AGENTIC_PLAN_V1 or something here AND in processCodeTransformSkipTests when backend allowlists everyone
1415
val transformCapabilities: List<String> = listOf(EXPLAINABILITY_V1),
1516
val customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS,
1617
val requestedConversions: RequestedConversions? = null, // only used for SQL conversions for now

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.panels.CodeModern
2828
import software.aws.toolkits.jetbrains.services.codemodernizer.panels.LoadingPanel
2929
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState
3030
import software.aws.toolkits.jetbrains.services.codemodernizer.toolwindow.CodeModernizerBottomToolWindowFactory
31+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isPlanComplete
3132
import software.aws.toolkits.resources.message
3233
import java.awt.BorderLayout
3334
import java.awt.Component
@@ -251,7 +252,7 @@ class CodeModernizerBottomWindowPanelManager(private val project: Project) : JPa
251252
TransformationStatus.PAUSED,
252253
TransformationStatus.COMPLETED,
253254
TransformationStatus.PARTIALLY_COMPLETED
254-
) && transformType != CodeTransformType.SQL_CONVERSION // no plan for SQL conversions
255+
) && transformType == CodeTransformType.LANGUAGE_UPGRADE && isPlanComplete(plan)
255256
) {
256257
addPlanToBanner()
257258
}

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.LOC_THR
2424
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact.Companion.MAPPER
2525
import software.aws.toolkits.jetbrains.services.codemodernizer.model.PlanTable
2626
import software.aws.toolkits.jetbrains.services.codemodernizer.plan.CodeModernizerPlanEditorProvider.Companion.MIGRATION_PLAN_KEY
27+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.combineTableRows
2728
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getAuthType
2829
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText
2930
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getLinesOfCodeSubmitted
@@ -76,7 +77,7 @@ class CodeModernizerPlanEditor(val project: Project, private val virtualFile: Vi
7677
// comes from "name" field of each progressUpdate in step zero of plan
7778
if (JOB_STATISTICS_TABLE_KEY in tableMapping) {
7879
val planTable = parseTableMapping(tableMapping)
79-
val linesOfCode = planTable?.let { getLinesOfCodeSubmitted(it) }
80+
val linesOfCode = getLinesOfCodeSubmitted(planTable)
8081
if (linesOfCode != null && linesOfCode > LOC_THRESHOLD && getAuthType(project) == CredentialSourceId.IamIdentityCenter) {
8182
val billingText = getBillingText(linesOfCode)
8283
val billingTextComponent =
@@ -98,15 +99,15 @@ class CodeModernizerPlanEditor(val project: Project, private val virtualFile: Vi
9899
add(billingTextComponent, CodeModernizerUIConstants.transformationPlanPlaneConstraint)
99100
}
100101
add(
101-
planTable?.let { transformationPlanInfo(it) },
102+
transformationPlanInfo(planTable),
102103
CodeModernizerUIConstants.transformationPlanPlaneConstraint,
103104
)
104105
}
105106
add(transformationPlanPanel(plan), CodeModernizerUIConstants.transformationPlanPlaneConstraint)
106-
// key "-1" reserved for appendix table
107+
// key "-1" reserved for appendix table; only 1 table there
107108
if (APPENDIX_TABLE_KEY in tableMapping) {
108109
add(
109-
tableMapping[APPENDIX_TABLE_KEY]?.let { MAPPER.readValue<PlanTable>(it) }?.let { transformationPlanAppendix(it) },
110+
tableMapping[APPENDIX_TABLE_KEY]?.get(0)?.let { MAPPER.readValue<PlanTable>(it) }?.let { transformationPlanAppendix(it) },
110111
CodeModernizerUIConstants.transformationPlanPlaneConstraint,
111112
)
112113
}
@@ -393,10 +394,17 @@ class CodeModernizerPlanEditor(val project: Project, private val virtualFile: Vi
393394
border = CodeModernizerUIConstants.DESCRIPTION_BORDER
394395
}
395396

396-
val table = tableMapping[step.id()]
397+
val tables = tableMapping[step.id()]
397398

398-
var parsedTable = table?.let {
399-
MAPPER.readValue<PlanTable>(it)
399+
val parsedTables = tables?.map { table ->
400+
MAPPER.readValue<PlanTable>(table)
401+
}
402+
403+
var parsedTable: PlanTable? = if (parsedTables?.size == 1) {
404+
parsedTables.first()
405+
} else {
406+
// for multiple tables under 1 step, the table headers are the same, so combine the rows and just show 1 combined table
407+
combineTableRows(parsedTables)
400408
}
401409

402410
if (parsedTable?.rows?.isEmpty() == true) {

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

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package software.aws.toolkits.jetbrains.services.codemodernizer.utils
55

66
import com.fasterxml.jackson.module.kotlin.readValue
7+
import com.intellij.grazie.utils.orFalse
78
import com.intellij.notification.NotificationAction
89
import com.intellij.openapi.application.runInEdt
910
import com.intellij.openapi.application.runWriteAction
@@ -285,20 +286,36 @@ fun findDownloadArtifactProgressUpdate(transformationSteps: List<TransformationS
285286
update.downloadArtifacts()?.firstOrNull()?.downloadArtifactId() != null
286287
}
287288

289+
// once dependency changes table (key of "1") available, plan is complete
290+
fun isPlanComplete(plan: TransformationPlan?) = plan?.transformationSteps()?.get(0)?.progressUpdates()?.any { update -> update.name() == "1" }.orFalse()
291+
288292
// "name" holds the ID of the corresponding plan step (where table will go) and "description" holds the plan data
289-
fun getTableMapping(stepZeroProgressUpdates: List<TransformationProgressUpdate>): Map<String, String> {
290-
if (stepZeroProgressUpdates.isNotEmpty()) {
291-
return stepZeroProgressUpdates.associate {
292-
it.name() to it.description()
293+
fun getTableMapping(stepZeroProgressUpdates: List<TransformationProgressUpdate>): Map<String, List<String>> =
294+
stepZeroProgressUpdates.groupBy(
295+
{ it.name() },
296+
{ it.description() }
297+
)
298+
299+
// ID of '0' reserved for job statistics table; only 1 table there
300+
fun parseTableMapping(tableMapping: Map<String, List<String>>): PlanTable {
301+
val statsTable = tableMapping[JOB_STATISTICS_TABLE_KEY]?.get(0) ?: error("No transformation statistics table found in GetPlan response")
302+
return MAPPER.readValue<PlanTable>(statsTable)
303+
}
304+
305+
// columns and name are shared between all PlanTables, so just combine the rows here
306+
fun combineTableRows(tables: List<PlanTable>?): PlanTable? {
307+
if (tables == null) {
308+
return null
309+
}
310+
val combinedTable = PlanTable(tables.first().columns, mutableListOf(), tables.first().name)
311+
tables.forEach { table ->
312+
table.rows.forEach { row ->
313+
combinedTable.rows.add(row)
293314
}
294-
} else {
295-
error("GetPlan response missing step 0 progress updates with table data")
296315
}
316+
return combinedTable
297317
}
298318

299-
fun parseTableMapping(tableMapping: Map<String, String>): PlanTable? =
300-
tableMapping[JOB_STATISTICS_TABLE_KEY]?.let { MAPPER.readValue<PlanTable>(it) }
301-
302319
fun getBillingText(linesOfCode: Int): String {
303320
val estimatedCost = String.format(Locale.US, "%.2f", linesOfCode.times(BILLING_RATE))
304321
return message("codemodernizer.migration_plan.header.billing_text", linesOfCode, BILLING_RATE, estimatedCost)

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

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

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

6+
import com.fasterxml.jackson.module.kotlin.readValue
67
import com.intellij.testFramework.LightVirtualFile
78
import io.mockk.every
89
import io.mockk.just
@@ -26,11 +27,15 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
2627
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
2728
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep
2829
import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
30+
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact.Companion.MAPPER
2931
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
32+
import software.aws.toolkits.jetbrains.services.codemodernizer.model.PlanTable
33+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.combineTableRows
3034
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createClientSideBuildUploadZip
3135
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText
3236
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getClientInstructionArtifactId
3337
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getTableMapping
38+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isPlanComplete
3439
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildFile
3540
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
3641
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken
@@ -224,10 +229,73 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
224229
val step0Update2 = TransformationProgressUpdate.builder().name("2").status("COMPLETED").description(apiChanges).build()
225230
val step0Update3 = TransformationProgressUpdate.builder().name("-1").status("COMPLETED").description(fileChanges).build()
226231
val actual = getTableMapping(listOf(step0Update0, step0Update1, step0Update2, step0Update3))
227-
val expected = mapOf("0" to jobStats, "1" to depChanges, "2" to apiChanges, "-1" to fileChanges)
232+
val expected = mapOf("0" to listOf(jobStats), "1" to listOf(depChanges), "2" to listOf(apiChanges), "-1" to listOf(fileChanges))
228233
assertThat(expected).isEqualTo(actual)
229234
}
230235

236+
@Test
237+
fun `combineTableRows combines multiple dependency tables correctly`() {
238+
val table1Json = """
239+
{"name":"Dependency changes", "columnNames":["dependencyName","action","currentVersion","targetVersion"],
240+
"rows":[{"dependencyName":"org.springframework.boot","action":"Update","currentVersion":"2.1","targetVersion":"2.4"}]}
241+
""".trimIndent()
242+
val table2Json = """
243+
{"name":"Dependency changes", "columnNames":["dependencyName","action","currentVersion","targetVersion"],
244+
"rows":[{"dependencyName":"junit","action":"Add","currentVersion":"","targetVersion":"4.13"}]}
245+
""".trimIndent()
246+
val tables = listOf(
247+
MAPPER.readValue<PlanTable>(table1Json),
248+
MAPPER.readValue<PlanTable>(table2Json)
249+
)
250+
val combinedTable = combineTableRows(tables)
251+
assertThat(combinedTable?.rows).hasSize(2)
252+
assertThat(combinedTable?.name).isEqualTo("Dependency changes")
253+
assertThat(combinedTable?.columns).hasSize(4)
254+
}
255+
256+
@Test
257+
fun `isPlanComplete returns true when plan has progress update with name '1'`() {
258+
// Arrange
259+
val plan = TransformationPlan.builder()
260+
.transformationSteps(
261+
listOf(
262+
TransformationStep.builder()
263+
.progressUpdates(
264+
listOf(
265+
TransformationProgressUpdate.builder()
266+
.name("1")
267+
.build()
268+
)
269+
)
270+
.build()
271+
)
272+
)
273+
.build()
274+
val result = isPlanComplete(plan)
275+
assertThat(result).isTrue()
276+
}
277+
278+
@Test
279+
fun `isPlanComplete returns false when plan has no progress update with name '1'`() {
280+
val plan = TransformationPlan.builder()
281+
.transformationSteps(
282+
listOf(
283+
TransformationStep.builder()
284+
.progressUpdates(
285+
listOf(
286+
TransformationProgressUpdate.builder()
287+
.name("2")
288+
.build()
289+
)
290+
)
291+
.build()
292+
)
293+
)
294+
.build()
295+
val result = isPlanComplete(plan)
296+
assertThat(result).isFalse()
297+
}
298+
231299
@Test
232300
fun `getClientInstructionArtifactId extracts artifact ID from transformation plan`() {
233301
val step1 = TransformationStep.builder()

0 commit comments

Comments
 (0)