Skip to content

Commit 5ac5260

Browse files
authored
Merge branch 'main' into statusCheck
2 parents 0d4c8cb + 48fc68a commit 5ac5260

File tree

59 files changed

+986
-517
lines changed

Some content is hidden

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

59 files changed

+986
-517
lines changed

.changes/3.48.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"date" : "2025-01-16",
3+
"version" : "3.48",
4+
"entries" : [ {
5+
"type" : "feature",
6+
"description" : "Enhance Q inline completion context fetching for better suggestion quality"
7+
}, {
8+
"type" : "feature",
9+
"description" : "/doc: Add error message if updated README is too large"
10+
}, {
11+
"type" : "bugfix",
12+
"description" : "/transform: always include button to start a new transformation at the end of a job"
13+
}, {
14+
"type" : "bugfix",
15+
"description" : "Amazon Q can update mvn and gradle build files"
16+
}, {
17+
"type" : "bugfix",
18+
"description" : "Fix doc generation for modules that are a part of the project"
19+
}, {
20+
"type" : "bugfix",
21+
"description" : "Amazon Q /dev: Remove hard-coded limits and instead rely server-side data to communicate number of code generations remaining"
22+
}, {
23+
"type" : "bugfix",
24+
"description" : "/transform: automatically open pre-build error logs when available"
25+
}, {
26+
"type" : "bugfix",
27+
"description" : "/doc: Fix code generation error when cancelling a documentation task"
28+
}, {
29+
"type" : "bugfix",
30+
"description" : "Amazon Q - update messaging for /doc agent"
31+
} ]
32+
}

.changes/3.49.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"date" : "2025-01-17",
3+
"version" : "3.49",
4+
"entries" : [ {
5+
"type" : "bugfix",
6+
"description" : "/review: Improved success rate of code reviews for certain workspace configurations"
7+
} ]
8+
}

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# _3.49_ (2025-01-17)
2+
- **(Bug Fix)** /review: Improved success rate of code reviews for certain workspace configurations
3+
4+
# _3.48_ (2025-01-16)
5+
- **(Feature)** Enhance Q inline completion context fetching for better suggestion quality
6+
- **(Feature)** /doc: Add error message if updated README is too large
7+
- **(Bug Fix)** /transform: always include button to start a new transformation at the end of a job
8+
- **(Bug Fix)** Amazon Q can update mvn and gradle build files
9+
- **(Bug Fix)** Fix doc generation for modules that are a part of the project
10+
- **(Bug Fix)** Amazon Q /dev: Remove hard-coded limits and instead rely server-side data to communicate number of code generations remaining
11+
- **(Bug Fix)** /transform: automatically open pre-build error logs when available
12+
- **(Bug Fix)** /doc: Fix code generation error when cancelling a documentation task
13+
- **(Bug Fix)** Amazon Q - update messaging for /doc agent
14+
115
# _3.47_ (2025-01-09)
216
- **(Bug Fix)** Fix issue where users are unable to login to Amazon Q if they have previously authenticated ([#5214](https://github.com/aws/aws-toolkit-jetbrains/issues/5214))
317
- **(Bug Fix)** Fix incorrect text shown while updating documentation in /doc

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.48-SNAPSHOT
5+
toolkitVersion=3.50-SNAPSHOT
66

77
# Publish Settings
88
publishToken=

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererCodeTestSession.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
3434
* Run UTG sessions are follow steps:
3535
* 1. Zipping project
3636
* 2. Creating Upload url & Upload to S3 bucket
37-
* 3. StartTestGeneration API -> Get JobId
38-
* 4. GetTestGeneration API
39-
* 5. ExportResultsArchieve API
4037
*/
4138
suspend fun run(codeTestChatHelper: CodeTestChatHelper, previousIterationContext: PreviousUTGIterationContext?): CodeTestResponseContext {
4239
try {
@@ -94,7 +91,8 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
9491
sourceZip,
9592
"SourceCode",
9693
CodeWhispererConstants.UploadTaskType.UTG,
97-
taskName
94+
taskName,
95+
CodeWhispererConstants.FeatureName.TEST_GENERATION
9896
)
9997

10098
sourceZipUploadResponse.uploadId()
@@ -113,11 +111,10 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
113111
sourceZipUploadResponse,
114112
testSummaryMessageId
115113
)
116-
// TODO send telemetry for upload duration
117114

118115
return codeTestResponseContext
119116
} catch (e: Exception) {
120-
LOG.debug(e) { "Error when creating tests for the current file" }
117+
LOG.debug(e) { "Error while creating zip and uploading to S3" }
121118
throw e
122119
}
123120
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import kotlinx.coroutines.CoroutineScope
1616
import kotlinx.coroutines.Job
1717
import kotlinx.coroutines.delay
1818
import kotlinx.coroutines.launch
19-
import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException
19+
import software.amazon.awssdk.core.exception.SdkServiceException
2020
import software.amazon.awssdk.services.codewhispererruntime.model.GetTestGenerationResponse
2121
import software.amazon.awssdk.services.codewhispererruntime.model.Range
2222
import software.amazon.awssdk.services.codewhispererruntime.model.StartTestGenerationResponse
@@ -38,9 +38,13 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.BuildAnd
3838
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.Session
3939
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.utils.combineBuildAndExecuteLogFiles
4040
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.calculateTotalLatency
41+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.CodeTestException
4142
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.sessionconfig.CodeTestSessionConfig
43+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.testGenStoppedError
4244
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
45+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
4346
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.promptReAuth
47+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.getTelemetryErrorMessage
4448
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
4549
import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
4650
import software.aws.toolkits.jetbrains.services.cwc.messages.CodeReference
@@ -67,7 +71,7 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
6771

6872
private fun throwIfCancelled(session: Session) {
6973
if (!session.isGeneratingTests) {
70-
error(message("testgen.message.cancelled"))
74+
testGenStoppedError()
7175
}
7276
}
7377

@@ -104,24 +108,38 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
104108
}
105109

106110
// 2nd API call: StartTestGeneration
107-
val startTestGenerationResponse = startTestGeneration(
108-
uploadId = createUploadUrlResponse.uploadId(),
109-
targetCode = listOf(
110-
TargetCode.builder()
111-
.relativeTargetPath(codeTestResponseContext.currentFileRelativePath.toString())
112-
.targetLineRangeList(
113-
if (selectionRange != null) {
114-
listOf(
115-
selectionRange
116-
)
117-
} else {
118-
emptyList()
119-
}
120-
)
121-
.build()
122-
),
123-
userInput = prompt
124-
)
111+
val startTestGenerationResponse = try {
112+
startTestGeneration(
113+
uploadId = createUploadUrlResponse.uploadId(),
114+
targetCode = listOf(
115+
TargetCode.builder()
116+
.relativeTargetPath(codeTestResponseContext.currentFileRelativePath.toString())
117+
.targetLineRangeList(
118+
if (selectionRange != null) {
119+
listOf(
120+
selectionRange
121+
)
122+
} else {
123+
emptyList()
124+
}
125+
)
126+
.build()
127+
),
128+
userInput = prompt
129+
)
130+
} catch (e: Exception) {
131+
val statusCode = when {
132+
e is SdkServiceException -> e.statusCode()
133+
else -> 400
134+
}
135+
LOG.error(e) { "Unexpected error while creating test generation job" }
136+
val errorMessage = getTelemetryErrorMessage(e, CodeWhispererConstants.FeatureName.TEST_GENERATION)
137+
throw CodeTestException(
138+
"CreateTestJobError: $errorMessage",
139+
"CreateTestJobError",
140+
message("testgen.error.generic_technical_error_message")
141+
)
142+
}
125143

126144
val job = startTestGenerationResponse.testGenerationJob()
127145
session.startTestGenerationRequestId = startTestGenerationResponse.responseMetadata().requestId()
@@ -173,7 +191,12 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
173191
}
174192
// update test summary card
175193
} else {
176-
throw Exception(message("testgen.message.failed"))
194+
// If job status is Completed and has no ShortAnswer then there might be some issue in the backend.
195+
throw CodeTestException(
196+
"TestGenFailedError: " + message("testgen.message.failed"),
197+
"TestGenFailedError",
198+
message("testgen.error.generic_technical_error_message")
199+
)
177200
}
178201
} else if (status == TestGenerationJobStatus.FAILED) {
179202
LOG.debug {
@@ -183,12 +206,16 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
183206
if (testGenerationResponse.testGenerationJob().shortAnswer() != null) {
184207
shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer())
185208
if (shortAnswer.stopIteration == "true") {
186-
throw Exception("${shortAnswer.planSummary}")
209+
throw CodeTestException("TestGenFailedError: ${shortAnswer.planSummary}", "TestGenFailedError", shortAnswer.planSummary)
187210
}
188211
}
189212

190-
// TODO: Modify text according to FnF
191-
throw Exception(message("testgen.message.failed"))
213+
// If job status is Failed and has no ShortAnswer then there might be some issue in the backend.
214+
throw CodeTestException(
215+
"TestGenFailedError: " + message("testgen.message.failed"),
216+
"TestGenFailedError",
217+
message("testgen.error.generic_technical_error_message")
218+
)
192219
} else {
193220
// In progress
194221
LOG.debug {
@@ -200,7 +227,7 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
200227
if (previousIterationContext == null && testGenerationResponse.testGenerationJob().shortAnswer() != null) {
201228
shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer())
202229
if (shortAnswer.stopIteration == "true") {
203-
throw Exception("${shortAnswer.planSummary}")
230+
throw CodeTestException("TestGenFailedError: ${shortAnswer.planSummary}", "TestGenFailedError", shortAnswer.planSummary)
204231
}
205232
codeTestChatHelper.updateAnswer(
206233
CodeTestChatMessageContent(
@@ -232,6 +259,11 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
232259
},
233260
{ e ->
234261
LOG.error(e) { "ExportResultArchive failed: ${e.message}" }
262+
throw CodeTestException(
263+
"ExportResultsArchiveError: ${e.message}",
264+
"ExportResultsArchiveError",
265+
message("testgen.error.generic_technical_error_message")
266+
)
235267
},
236268
{ startTime ->
237269
LOG.info { "ExportResultArchive latency: ${calculateTotalLatency(startTime, Instant.now())}" }
@@ -492,15 +524,19 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
492524
try {
493525
launchTestGenFlow(prompt, codeTestChatHelper, previousIterationContext, selectionRange)
494526
} catch (e: Exception) {
527+
// reset number of unitTestGenerated to null
528+
session.numberOfUnitTestCasesGenerated = null
495529
// Add an answer for displaying error message
496-
var errorMessage = e.message
497-
if (e is JsonParseException) {
498-
errorMessage = message("testgen.error.generic_error_message")
530+
val errorMessage = when {
531+
e is CodeTestException &&
532+
e.message?.startsWith("CreateTestJobError: Maximum") == true ->
533+
message("testgen.error.maximum_generations_reach")
534+
535+
e is CodeTestException -> e.uiMessage
536+
e is JsonParseException -> message("testgen.error.generic_technical_error_message")
537+
else -> message("testgen.error.generic_error_message")
499538
}
500539

501-
if (e is CodeWhispererRuntimeException) {
502-
errorMessage = message("testgen.error.maximum_generations_reach")
503-
}
504540
codeTestChatHelper.addAnswer(
505541
CodeTestChatMessageContent(
506542
message = errorMessage,
@@ -518,8 +554,8 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
518554
jobGroup = session.testGenerationJobGroupName,
519555
jobId = session.testGenerationJob,
520556
result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed,
521-
reason = e.javaClass.name,
522-
reasonDesc = e.message,
557+
reason = (e as CodeTestException).code ?: "DefaultError",
558+
reasonDesc = if (e.message == message("testgen.message.cancelled")) "${e.code}: ${e.message}" else e.message,
523559
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
524560
isCodeBlockSelected = session.isCodeBlockSelected,
525561
artifactsUploadDuration = session.artifactUploadDuration,

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import com.intellij.diff.DiffManagerEx
99
import com.intellij.diff.requests.SimpleDiffRequest
1010
import com.intellij.ide.BrowserUtil
1111
import com.intellij.openapi.application.ApplicationManager
12-
import com.intellij.openapi.fileEditor.FileDocumentManager
1312
import com.intellij.openapi.fileEditor.FileEditorManager
1413
import com.intellij.openapi.project.Project
1514
import com.intellij.openapi.project.guessProjectDir
@@ -452,7 +451,6 @@ class CodeTestChatController(
452451
var charDifference = 0
453452
var generatedFileContent = ""
454453
var selectedFileContent = ""
455-
var latencyOfTestGeneration = 0.0
456454

457455
when (message.actionID) {
458456
"utg_view_diff" -> {
@@ -474,16 +472,14 @@ class CodeTestChatController(
474472
)
475473
session.openedDiffFile = FileEditorManager.getInstance(context.project).selectedEditor?.file
476474
ApplicationManager.getApplication().runReadAction {
477-
generatedFileContent = getFileContentAtTestFilePath(
478-
session.projectRoot,
479-
session.testFileRelativePathToProjectRoot
480-
)
481-
val selectedFile = FileEditorManager.getInstance(context.project).selectedEditor?.file
482-
selectedFileContent = selectedFile?.let {
483-
FileDocumentManager.getInstance().getDocument(it)?.text
484-
}.orEmpty()
475+
generatedFileContent = getGeneratedFileContent(session)
485476
}
486477

478+
selectedFileContent = getFileContentAtTestFilePath(
479+
session.projectRoot,
480+
session.testFileRelativePathToProjectRoot,
481+
)
482+
487483
// Line difference calculation: linesOfCodeGenerated = number of lines in generated test file - number of lines in original test file
488484
numberOfLinesGenerated = generatedFileContent.lines().size
489485
numberOfLinesSelected = selectedFileContent.lines().size
@@ -496,7 +492,7 @@ class CodeTestChatController(
496492

497493
session.linesOfCodeGenerated = lineDifference.coerceAtLeast(0)
498494
session.charsOfCodeGenerated = charDifference.coerceAtLeast(0)
499-
latencyOfTestGeneration = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration)
495+
session.latencyOfTestGeneration = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration)
500496
UiTelemetry.click(null as Project?, "unitTestGeneration_viewDiff")
501497

502498
val buttonList = mutableListOf<Button>()
@@ -611,7 +607,7 @@ class CodeTestChatController(
611607
acceptedCharactersCount = session.charsOfCodeGenerated?.toLong(),
612608
generatedCharactersCount = session.charsOfCodeGenerated?.toLong(),
613609
result = MetricResult.Succeeded,
614-
perfClientLatency = latencyOfTestGeneration,
610+
perfClientLatency = session.latencyOfTestGeneration,
615611
isCodeBlockSelected = session.isCodeBlockSelected,
616612
artifactsUploadDuration = session.artifactUploadDuration,
617613
buildPayloadBytes = session.srcPayloadSize,
@@ -807,7 +803,7 @@ class CodeTestChatController(
807803
acceptedCharactersCount = 0,
808804
generatedCharactersCount = session.charsOfCodeGenerated?.toLong(),
809805
result = MetricResult.Succeeded,
810-
perfClientLatency = latencyOfTestGeneration,
806+
perfClientLatency = session.latencyOfTestGeneration,
811807
isCodeBlockSelected = session.isCodeBlockSelected,
812808
artifactsUploadDuration = session.artifactUploadDuration,
813809
buildPayloadBytes = session.srcPayloadSize,
@@ -1071,6 +1067,12 @@ class CodeTestChatController(
10711067
}
10721068
}
10731069

1070+
// Return generated test file content
1071+
private fun getGeneratedFileContent(session: Session): String {
1072+
val generateFileContent = session.generatedTestDiffs[session.testFileRelativePathToProjectRoot].toString()
1073+
return generateFileContent
1074+
}
1075+
10741076
/*
10751077
If shortAnswer has buildCommand, use it, if it doesn't hardcode it according to the user type(internal or not)
10761078
private fun getBuildCommand(tabId: String): String {

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/session/Session.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ data class Session(val tabId: String) {
2828
var linesOfCodeGenerated: Int? = null
2929
var charsOfCodeGenerated: Int? = null
3030
var startTimeOfTestGeneration: Double = 0.0
31+
var latencyOfTestGeneration: Double = 0.0
3132
var isCodeBlockSelected: Boolean = false
3233
var srcPayloadSize: Long = 0
3334
var srcZipFileSize: Long = 0

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/storage/ChatSessionStorage.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,8 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.Session
88
class ChatSessionStorage {
99
private val sessions = mutableMapOf<String, Session>()
1010

11-
private fun createSession(tabId: String): Session {
12-
val session = Session(tabId)
13-
sessions[tabId] = session
14-
return session
15-
}
16-
17-
fun getSession(tabId: String): Session = sessions[tabId] ?: createSession(tabId)
11+
@Synchronized
12+
fun getSession(tabId: String): Session = sessions.getOrPut(tabId) { Session(tabId) }
1813

1914
fun deleteSession(tabId: String) {
2015
sessions.remove(tabId)

0 commit comments

Comments
 (0)