Skip to content

Commit 8851df2

Browse files
authored
Code transform feature - Human in the loop (#4345)
1 parent 5652f94 commit 8851df2

File tree

56 files changed

+1908
-71
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1908
-71
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" : "Human in the loop - Adding human intervention to help update dependencies during the Amazon Q Transformation process"
4+
}

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mockito = "5.11.0"
2222
mockitoKotlin = "5.2.1"
2323
mockk = "1.13.10"
2424
node-gradle = "7.0.1"
25-
telemetryGenerator = "1.0.206"
25+
telemetryGenerator = "1.0.207"
2626
testLogger = "4.0.0"
2727
testRetry = "1.5.2"
2828
# test-only; platform provides slf4j transitively at runtime. <233, 1.7.36; >=233, 2.0.9

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/clients/FeatureDevClient.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class FeatureDevClient(private val project: Project) {
148148
suspend fun exportTaskAssistResultArchive(conversationId: String): MutableList<ByteArray> = amazonQStreamingClient.exportResultArchive(
149149
conversationId,
150150
ExportIntent.TASK_ASSIST,
151+
null,
151152
{ e ->
152153
LOG.error(e) { "TaskAssist - ExportResultArchive stream exportId=$conversationId exportIntent=${ExportIntent.TASK_ASSIST} Failed: ${e.message} " }
153154
},

plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClientTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class AmazonQStreamingClientTest : AmazonQTestBase() {
7676
val requestCaptor = argumentCaptor<ExportResultArchiveRequest>()
7777
val handlerCaptor = argumentCaptor<ExportResultArchiveResponseHandler>()
7878

79-
amazonQStreamingClient.exportResultArchive("test-id", ExportIntent.TRANSFORMATION, {}, {})
79+
amazonQStreamingClient.exportResultArchive("test-id", ExportIntent.TRANSFORMATION, null, {}, {})
8080
argumentCaptor<ExportResultArchiveRequest, ExportResultArchiveResponseHandler>().apply {
8181
verify(streamingBearerClient).exportResultArchive(requestCaptor.capture(), handlerCaptor.capture())
8282
}

plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/clients/FeatureDevClientTest.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,19 @@ class FeatureDevClientTest : FeatureDevTestBase() {
153153

154154
@Test
155155
fun `check exportTaskAssistResultArchive`() = runTest {
156-
whenever(amazonQStreamingClient.exportResultArchive(any<String>(), any<ExportIntent>(), any(), any())) doReturn exampleExportResultArchiveResponse
156+
whenever(
157+
amazonQStreamingClient.exportResultArchive(
158+
any<String>(),
159+
any<ExportIntent>(),
160+
eq(null),
161+
any(),
162+
any()
163+
)
164+
) doReturn exampleExportResultArchiveResponse
157165

158166
val actual = featureDevClient.exportTaskAssistResultArchive("1234")
159167

160-
verify(amazonQStreamingClient).exportResultArchive(eq("1234"), eq(ExportIntent.TASK_ASSIST), any(), any())
168+
verify(amazonQStreamingClient).exportResultArchive(eq("1234"), eq(ExportIntent.TASK_ASSIST), eq(null), any(), any())
161169
verifyNoInteractions(bearerClient)
162170
verifyNoInteractions(streamingBearerClient)
163171
verifyNoMoreInteractions(amazonQStreamingClient)

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

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,32 @@ import com.intellij.openapi.vcs.changes.patch.ImportToShelfExecutor
1515
import com.intellij.openapi.vfs.LocalFileSystem
1616
import com.intellij.openapi.vfs.VirtualFile
1717
import kotlinx.coroutines.launch
18+
import kotlinx.coroutines.withContext
1819
import software.aws.toolkits.core.utils.error
1920
import software.aws.toolkits.core.utils.exists
2021
import software.aws.toolkits.core.utils.getLogger
2122
import software.aws.toolkits.core.utils.info
23+
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
2224
import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
2325
import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
2426
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact
27+
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformHilDownloadArtifact
2528
import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
2629
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.TROUBLESHOOTING_URL_DOWNLOAD_DIFF
30+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir
2731
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction
2832
import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
2933
import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
3034
import software.aws.toolkits.resources.message
35+
import software.aws.toolkits.telemetry.CodeTransformApiNames
36+
import java.io.File
3137
import java.nio.file.Files
3238
import java.nio.file.Path
3339
import java.time.Instant
3440
import java.util.concurrent.atomic.AtomicBoolean
3541

3642
data class DownloadArtifactResult(val artifact: CodeModernizerArtifact?, val zipPath: String)
43+
3744
class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient) {
3845
private val telemetry = CodeTransformTelemetryManager.getInstance(project)
3946
private val downloadedArtifacts = mutableMapOf<JobId, Path>()
@@ -58,6 +65,50 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
5865
)
5966
}
6067

68+
private suspend fun unzipToPath(byteArrayList: List<ByteArray>, outputDirPath: Path? = null): Pair<Path, Int> {
69+
val zipFilePath = withContext(getCoroutineBgContext()) {
70+
if (outputDirPath == null) {
71+
Files.createTempFile(null, ".zip")
72+
} else {
73+
Files.createTempFile(outputDirPath, null, ".zip")
74+
}
75+
}
76+
var totalDownloadBytes = 0
77+
withContext(getCoroutineBgContext()) {
78+
Files.newOutputStream(zipFilePath).use {
79+
for (bytes in byteArrayList) {
80+
it.write(bytes)
81+
totalDownloadBytes += bytes.size
82+
}
83+
}
84+
}
85+
return zipFilePath to totalDownloadBytes
86+
}
87+
88+
suspend fun downloadHilArtifact(jobId: JobId, artifactId: String, tmpDir: File): CodeTransformHilDownloadArtifact? {
89+
val downloadResultsResponse = try {
90+
clientAdaptor.downloadExportResultArchive(jobId, artifactId)
91+
} catch (e: Exception) {
92+
val errorMessage = "Unexpected error when downloading hil artifact: ${e.localizedMessage}"
93+
LOG.error { errorMessage }
94+
telemetry.apiError(errorMessage, CodeTransformApiNames.ExportResultArchive, jobId = jobId.id)
95+
throw e
96+
}
97+
98+
return try {
99+
val tmpPath = tmpDir.toPath()
100+
val (downloadZipFilePath, _) = unzipToPath(downloadResultsResponse, tmpPath)
101+
LOG.info { "Successfully converted the hil artifact download to a zip at ${downloadZipFilePath.toAbsolutePath()}." }
102+
CodeTransformHilDownloadArtifact.create(downloadZipFilePath, getPathToHilArtifactDir(tmpPath))
103+
} catch (e: Exception) {
104+
// In case if unzip or file operations fail
105+
val errorMessage = "Unexpected error when saving downloaded hil artifact: ${e.localizedMessage}"
106+
telemetry.error(errorMessage)
107+
LOG.error { errorMessage }
108+
null
109+
}
110+
}
111+
61112
suspend fun downloadArtifact(job: JobId): DownloadArtifactResult {
62113
isCurrentlyDownloading.set(true)
63114
val downloadStartTime = Instant.now()
@@ -83,16 +134,10 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
83134

84135
// 3. Convert to zip
85136
LOG.info { "Downloaded the export result archive, about to transform to zip" }
86-
val path = Files.createTempFile(null, ".zip")
87-
var totalDownloadBytes = 0
88-
Files.newOutputStream(path).use {
89-
for (bytes in downloadResultsResponse) {
90-
it.write(bytes)
91-
totalDownloadBytes += bytes.size
92-
}
93-
}
94-
LOG.info { "Successfully converted the download to a zip at ${path.toAbsolutePath()}." }
137+
138+
val (path, totalDownloadBytes) = unzipToPath(downloadResultsResponse)
95139
val zipPath = path.toAbsolutePath().toString()
140+
LOG.info { "Successfully converted the download to a zip at $zipPath." }
96141

97142
// 4. Deserialize zip to CodeModernizerArtifact
98143
var telemetryErrorMessage: String? = null

0 commit comments

Comments
 (0)