Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(amazonq): UTG build and execute for internal users. #5436

Open
wants to merge 29 commits into
base: feature/build-execute
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
24a0832
add build-execute code
Randall-Jiang Feb 21, 2025
4168e78
address comment
Randall-Jiang Feb 21, 2025
b5de261
create progress bar for fixing build failure
Randall-Jiang Feb 21, 2025
9cf1786
fix the bug which might cause user can not execute the build command …
Randall-Jiang Feb 24, 2025
ca2c128
fix format error
Randall-Jiang Feb 24, 2025
9151dce
correct the logic to send the telemetry
Randall-Jiang Feb 25, 2025
b5792bc
addressed comment
Randall-Jiang Feb 25, 2025
5231789
nit
Randall-Jiang Feb 25, 2025
9e323fe
addressing comments
Randall-Jiang Feb 25, 2025
3601d49
add PATH
Randall-Jiang Feb 28, 2025
fc8d07b
add gradle file for groovy version of the gradle build script
Randall-Jiang Feb 28, 2025
d195b1a
fix UI error
Randall-Jiang Mar 3, 2025
7e6a367
Fix lint errors
laileni-aws Mar 3, 2025
2c3ddba
Merge branch 'feature/build-execute' into build-execute
laileni-aws Mar 3, 2025
43dced6
Merge from Feature/build-execute
laileni-aws Mar 4, 2025
bc510d0
Merge branch 'feature/build-execute' into randal/build
laileni-aws Mar 4, 2025
3c6c33c
Refactoring Build and execute
laileni-aws Mar 4, 2025
d139695
Revert "Refactoring Build and execute"
laileni-aws Mar 4, 2025
b257fed
Refactoring Build and execute
laileni-aws Mar 4, 2025
1b76a80
Fixing build and execute command issue
laileni-aws Mar 4, 2025
e87fe92
Bug fixes in build and execute
laileni-aws Mar 6, 2025
3e129b2
Progress bar cancel UX changes
laileni-aws Mar 6, 2025
3dcde41
Fixes
laileni-aws Mar 7, 2025
22b1e81
Merge branch 'feature/build-execute' into randal/build
laileni-aws Mar 7, 2025
931fca3
Fixes
laileni-aws Mar 7, 2025
27b22d5
Modified impl of progress bar cancel functionality and some UX change…
laileni-aws Mar 7, 2025
6d039ae
Merge branch 'feature/build-execute' into randal/build
laileni-aws Mar 7, 2025
f7d450e
Minor fixes and refactoring in CTCChatController, CWSPRUTGChatManager…
laileni-aws Mar 7, 2025
e770e53
Removing commented code
laileni-aws Mar 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mockitoKotlin = "5.4.0"
mockk = "1.13.10"
nimbus-jose-jwt = "9.40"
node-gradle = "7.0.2"
telemetryGenerator = "1.0.297"
telemetryGenerator = "1.0.299"
testLogger = "4.0.0"
testRetry = "1.5.10"
# test-only; platform provides slf4j transitively at runtime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,22 @@ val cancelTestGenButton = Button(
icon = "cancel"
)

val cancelTestGenBuildAndExecuteButton = Button(
id = CodeTestButtonId.StopTestGenBuildAndExecution.id,
text = message("general.cancel"),
icon = "cancel"
)

fun testGenProgressField(value: Int) = ProgressField(
status = "default",
text = message("testgen.progressbar.generate_unit_tests"),
value = value,
valueText = "$value%",
actions = listOf(cancelTestGenButton)
)

val buildAndExecuteProgrogressField = ProgressField(
status = "default",
text = message("testgen.progressbar.build_and_execute"),
actions = listOf(cancelTestGenBuildAndExecuteButton)
)
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.model.ShortAnswer
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.BuildAndExecuteProgressStatus
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.Session
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.utils.combineBuildAndExecuteLogFiles
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.calculateTotalLatency
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.CodeTestException
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.fileTooLarge
Expand All @@ -63,6 +62,7 @@
import java.nio.file.Paths
import java.time.Duration
import java.time.Instant
import java.util.UUID
import java.util.concurrent.atomic.AtomicBoolean
import java.util.zip.ZipInputStream

Expand All @@ -87,13 +87,15 @@
) {
// 1st API call: Zip project and call CreateUploadUrl
val session = codeTestChatHelper.getActiveSession()
session.isGeneratingTests = true
session.iteration++
if (session.testGenerationJobGroupName.isEmpty()) {
session.testGenerationJobGroupName = UUID.randomUUID().toString()
}

// Set the Progress bar to "Generating unit tests..."
codeTestChatHelper.updateUI(
promptInputDisabledState = true,
promptInputProgress = testGenProgressField(0),
promptInputProgress = session.listOfTestGenerationJobId.takeUnless { it.isEmpty() }
?.let { buildAndExecuteProgrogressField }
?: testGenProgressField(0)
)

val codeTestResponseContext = createUploadUrl(codeTestChatHelper, previousIterationContext)
Expand All @@ -105,7 +107,7 @@
fileTooLarge()
}

val createUploadUrlResponse = codeTestResponseContext.createUploadUrlResponse ?: return
val createUploadUrlResponse = codeTestResponseContext.createUploadUrlResponse
throwIfCancelled(session)

LOG.debug {
Expand Down Expand Up @@ -137,7 +139,8 @@
)
.build()
),
userInput = prompt
userInput = prompt,
testGenerationJobGroupName = session.testGenerationJobGroupName
)
delay(200)
response?.testGenerationJob() != null
Expand Down Expand Up @@ -166,11 +169,12 @@
session.startTestGenerationRequestId = startTestGenerationResponse.responseMetadata().requestId()
session.testGenerationJobGroupName = job.testGenerationJobGroupName()
session.testGenerationJob = job.testGenerationJobId()
session.listOfTestGenerationJobId += job.testGenerationJobId()
throwIfCancelled(session)

// 3rd API call: Step 3: Polling mechanism on test job status with getTestGenStatus getTestGeneration
var finished = false
var testGenerationResponse: GetTestGenerationResponse? = null
var testGenerationResponse: GetTestGenerationResponse?

var shortAnswer = ShortAnswer()
LOG.debug {
Expand Down Expand Up @@ -198,6 +202,7 @@
// Setting default value to 0 if the value is null or invalid
session.numberOfUnitTestCasesGenerated = shortAnswer.numberOfTestMethods
session.testFileRelativePathToProjectRoot = getTestFilePathRelativeToRoot(shortAnswer)
session.shortAnswer = shortAnswer

// update test summary card in success case
if (previousIterationContext == null) {
Expand Down Expand Up @@ -261,7 +266,11 @@
}
codeTestChatHelper.updateUI(
promptInputDisabledState = true,
promptInputProgress = testGenProgressField(progressRate),
promptInputProgress = if (session.listOfTestGenerationJobId.size == 1) {
testGenProgressField(progressRate)
} else {
buildAndExecuteProgrogressField
}
)
}

Expand Down Expand Up @@ -294,7 +303,6 @@
val result = byteArray.reduce { acc, next -> acc + next } // To map the result it is needed to combine the full byte array
storeGeneratedTestDiffs(result, session)
if (!session.isGeneratingTests) {
// TODO: Modify text according to FnF
codeTestChatHelper.addAnswer(
CodeTestChatMessageContent(
message = message("testgen.error.generic_technical_error_message"),
Expand Down Expand Up @@ -342,7 +350,7 @@
session.viewDiffMessageId = viewDiffMessageId
codeTestChatHelper.updateUI(
promptInputDisabledState = false,
promptInputPlaceholder = "Specify a function(s) in the current file(optional)",
// promptInputPlaceholder = "Specify a function(s) in the current file(optional)",
promptInputProgress = testGenCompletedField,
)
} else {
Expand Down Expand Up @@ -468,21 +476,21 @@
} else {
previousIterationContext.selectedFile
}

val combinedBuildAndExecuteLogFile = combineBuildAndExecuteLogFiles(
previousIterationContext?.buildLogFile,
previousIterationContext?.testLogFile
)
val codeTestSessionConfig = CodeTestSessionConfig(file, project, combinedBuildAndExecuteLogFile)
val codeTestSessionConfig = CodeTestSessionConfig(file, project, previousIterationContext?.buildLogFile)
codeTestChatHelper.getActiveSession().projectRoot = codeTestSessionConfig.projectRoot.path

val codeTestSessionContext = CodeTestSessionContext(project, codeTestSessionConfig)
val codeWhispererCodeTestSession = CodeWhispererCodeTestSession(codeTestSessionContext)
return codeWhispererCodeTestSession.run(codeTestChatHelper, previousIterationContext)
}

private fun startTestGeneration(uploadId: String, targetCode: List<TargetCode>, userInput: String): StartTestGenerationResponse =
CodeWhispererClientAdaptor.getInstance(project).startTestGeneration(uploadId, targetCode, userInput)
private fun startTestGeneration(
uploadId: String,
targetCode: List<TargetCode>,
userInput: String,
testGenerationJobGroupName: String,
): StartTestGenerationResponse =
CodeWhispererClientAdaptor.getInstance(project).startTestGeneration(uploadId, targetCode, userInput, testGenerationJobGroupName)

private fun getTestGenerationStatus(jobId: String, jobGroupName: String): GetTestGenerationResponse =
CodeWhispererClientAdaptor.getInstance(project).getTestGeneration(jobId, jobGroupName)
Expand Down Expand Up @@ -566,28 +574,47 @@
canBeVoted = false
)
)

AmazonqTelemetry.utgGenerateTests(
cwsprChatProgrammingLanguage = session.programmingLanguage.languageId,
hasUserPromptSupplied = session.hasUserPromptSupplied,
isFileInWorkspace = true,
isSupportedLanguage = true,
credentialStartUrl = getStartUrl(project),
jobGroup = session.testGenerationJobGroupName,
jobId = session.testGenerationJob,
result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed,
reason = (e as CodeTestException).code ?: "DefaultError",
reasonDesc = if (e.message == message("testgen.message.cancelled")) "${e.code}: ${e.message}" else e.message,
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
isCodeBlockSelected = session.isCodeBlockSelected,
artifactsUploadDuration = session.artifactUploadDuration,
buildPayloadBytes = session.srcPayloadSize,
buildZipFileBytes = session.srcZipFileSize,
requestId = session.startTestGenerationRequestId
)
if (session.listOfTestGenerationJobId.size < 2) {
AmazonqTelemetry.utgGenerateTests(

Check warning on line 578 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt

View workflow job for this annotation

GitHub Actions / qodana

Usage of redundant or deprecated syntax or deprecated symbols

'AmazonqTelemetry' is deprecated. Use type-safe metric builders
cwsprChatProgrammingLanguage = session.programmingLanguage.languageId,
hasUserPromptSupplied = session.hasUserPromptSupplied,
isFileInWorkspace = true,
isSupportedLanguage = true,
credentialStartUrl = getStartUrl(project),
jobGroup = session.testGenerationJobGroupName,
jobId = session.testGenerationJob,
result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed,
reason = (e as CodeTestException).code ?: "DefaultError",
reasonDesc = if (e.message == message("testgen.message.cancelled")) "${e.code}: ${e.message}" else e.message,
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
isCodeBlockSelected = session.isCodeBlockSelected,
artifactsUploadDuration = session.artifactUploadDuration,
buildPayloadBytes = session.srcPayloadSize,
buildZipFileBytes = session.srcZipFileSize,
requestId = session.startTestGenerationRequestId
)
} else {
AmazonqTelemetry.unitTestGeneration(
cwsprChatProgrammingLanguage = session.programmingLanguage.languageId,
hasUserPromptSupplied = session.hasUserPromptSupplied,
isSupportedLanguage = true,
credentialStartUrl = getStartUrl(project),
jobGroup = session.testGenerationJobGroupName,
jobId = session.testGenerationJob,
result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed,
reason = (e as CodeTestException).code ?: "DefaultError",
reasonDesc = if (e.message == message("testgen.message.cancelled")) "${e.code}: ${e.message}" else e.message,

Check warning

Code scanning / QDJVMC

Usage of redundant or deprecated syntax or deprecated symbols Warning

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
isCodeBlockSelected = session.isCodeBlockSelected,
artifactsUploadDuration = session.artifactUploadDuration,
buildZipFileBytes = session.srcZipFileSize,
requestId = session.startTestGenerationRequestId
)
}
session.isGeneratingTests = false
} finally {
// Reset the flow if there is any error
codeTestChatHelper.sendUpdatePromptProgress(session.tabId, null)
if (!session.isGeneratingTests) {
codeTestChatHelper.updateUI(
promptInputProgress = cancellingProgressField
Expand Down
Loading
Loading