From 5174198450c5a7180f251ddc234ffdf6af5c2442 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Wed, 5 Feb 2025 20:22:09 +0000 Subject: [PATCH 01/12] Release 1.46.0 --- package-lock.json | 4 +- packages/amazonq/.changes/1.46.0.json | 38 +++++++++++++++++++ ...-22f55c14-bd62-49d7-aa68-3ab3cc8f0929.json | 4 -- ...-5c9f7fbc-1333-4c28-a049-7b17a17a7cea.json | 4 -- ...-c3484e6b-4093-4d35-8964-b5d07fb76469.json | 4 -- ...-ca03bdf5-a707-479e-9405-e9ac3b73e30a.json | 4 -- ...-dc78e630-6320-4297-9ae9-7a19891f5357.json | 4 -- ...-e2bb3c83-52e8-4ae9-aedb-844e8780971b.json | 4 -- ...-b63d765a-24f9-44e6-b826-b905f35e67d1.json | 4 -- ...-d4b1f56f-fbfd-43e9-b4e1-e2c972dcf197.json | 4 -- packages/amazonq/CHANGELOG.md | 11 ++++++ packages/amazonq/package.json | 2 +- 12 files changed, 52 insertions(+), 35 deletions(-) create mode 100644 packages/amazonq/.changes/1.46.0.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-22f55c14-bd62-49d7-aa68-3ab3cc8f0929.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-5c9f7fbc-1333-4c28-a049-7b17a17a7cea.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-c3484e6b-4093-4d35-8964-b5d07fb76469.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-ca03bdf5-a707-479e-9405-e9ac3b73e30a.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-dc78e630-6320-4297-9ae9-7a19891f5357.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-e2bb3c83-52e8-4ae9-aedb-844e8780971b.json delete mode 100644 packages/amazonq/.changes/next-release/Feature-b63d765a-24f9-44e6-b826-b905f35e67d1.json delete mode 100644 packages/amazonq/.changes/next-release/Feature-d4b1f56f-fbfd-43e9-b4e1-e2c972dcf197.json diff --git a/package-lock.json b/package-lock.json index 5fa0d8b6865..cd775bdd02c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -23904,7 +23904,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.46.0-SNAPSHOT", + "version": "1.46.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/.changes/1.46.0.json b/packages/amazonq/.changes/1.46.0.json new file mode 100644 index 00000000000..1253cbe3d01 --- /dev/null +++ b/packages/amazonq/.changes/1.46.0.json @@ -0,0 +1,38 @@ +{ + "date": "2025-02-05", + "version": "1.46.0", + "entries": [ + { + "type": "Bug Fix", + "description": "Citation links are not clickable as numbers, but appear as non-clickable texts" + }, + { + "type": "Bug Fix", + "description": "Fix language server start failure in AL2023 ARM64" + }, + { + "type": "Bug Fix", + "description": "/review: Auto-review issues did not populate code issues list" + }, + { + "type": "Bug Fix", + "description": "Amazon Q: Fix code upload error when using /dev or /doc on Remote SSH" + }, + { + "type": "Bug Fix", + "description": "/test placeholder text aligned across IDEs" + }, + { + "type": "Bug Fix", + "description": "Inline: Typos in the first example suggestion" + }, + { + "type": "Feature", + "description": "Inline suggestions: Pre-fetch recommendations to reduce suggestion latency." + }, + { + "type": "Feature", + "description": "Added github issue link and description to the chat answer feedback form" + } + ] +} \ No newline at end of file diff --git a/packages/amazonq/.changes/next-release/Bug Fix-22f55c14-bd62-49d7-aa68-3ab3cc8f0929.json b/packages/amazonq/.changes/next-release/Bug Fix-22f55c14-bd62-49d7-aa68-3ab3cc8f0929.json deleted file mode 100644 index ba2818371ba..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-22f55c14-bd62-49d7-aa68-3ab3cc8f0929.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Citation links are not clickable as numbers, but appear as non-clickable texts" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-5c9f7fbc-1333-4c28-a049-7b17a17a7cea.json b/packages/amazonq/.changes/next-release/Bug Fix-5c9f7fbc-1333-4c28-a049-7b17a17a7cea.json deleted file mode 100644 index 783359087ea..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-5c9f7fbc-1333-4c28-a049-7b17a17a7cea.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Fix language server start failure in AL2023 ARM64" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-c3484e6b-4093-4d35-8964-b5d07fb76469.json b/packages/amazonq/.changes/next-release/Bug Fix-c3484e6b-4093-4d35-8964-b5d07fb76469.json deleted file mode 100644 index 694495c26ae..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-c3484e6b-4093-4d35-8964-b5d07fb76469.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "/review: Auto-review issues did not populate code issues list" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-ca03bdf5-a707-479e-9405-e9ac3b73e30a.json b/packages/amazonq/.changes/next-release/Bug Fix-ca03bdf5-a707-479e-9405-e9ac3b73e30a.json deleted file mode 100644 index 4399da617e7..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-ca03bdf5-a707-479e-9405-e9ac3b73e30a.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Amazon Q: Fix code upload error when using /dev or /doc on Remote SSH" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-dc78e630-6320-4297-9ae9-7a19891f5357.json b/packages/amazonq/.changes/next-release/Bug Fix-dc78e630-6320-4297-9ae9-7a19891f5357.json deleted file mode 100644 index e34722b9aac..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-dc78e630-6320-4297-9ae9-7a19891f5357.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "/test placeholder text aligned across IDEs" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-e2bb3c83-52e8-4ae9-aedb-844e8780971b.json b/packages/amazonq/.changes/next-release/Bug Fix-e2bb3c83-52e8-4ae9-aedb-844e8780971b.json deleted file mode 100644 index 55ce7a614a9..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-e2bb3c83-52e8-4ae9-aedb-844e8780971b.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Inline: Typos in the first example suggestion" -} diff --git a/packages/amazonq/.changes/next-release/Feature-b63d765a-24f9-44e6-b826-b905f35e67d1.json b/packages/amazonq/.changes/next-release/Feature-b63d765a-24f9-44e6-b826-b905f35e67d1.json deleted file mode 100644 index 595e48f0026..00000000000 --- a/packages/amazonq/.changes/next-release/Feature-b63d765a-24f9-44e6-b826-b905f35e67d1.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Feature", - "description": "Inline suggestions: Pre-fetch recommendations to reduce suggestion latency." -} diff --git a/packages/amazonq/.changes/next-release/Feature-d4b1f56f-fbfd-43e9-b4e1-e2c972dcf197.json b/packages/amazonq/.changes/next-release/Feature-d4b1f56f-fbfd-43e9-b4e1-e2c972dcf197.json deleted file mode 100644 index 065aad75325..00000000000 --- a/packages/amazonq/.changes/next-release/Feature-d4b1f56f-fbfd-43e9-b4e1-e2c972dcf197.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Feature", - "description": "Added github issue link and description to the chat answer feedback form" -} diff --git a/packages/amazonq/CHANGELOG.md b/packages/amazonq/CHANGELOG.md index 8e8dd546b83..fa9896f64f1 100644 --- a/packages/amazonq/CHANGELOG.md +++ b/packages/amazonq/CHANGELOG.md @@ -1,3 +1,14 @@ +## 1.46.0 2025-02-05 + +- **Bug Fix** Citation links are not clickable as numbers, but appear as non-clickable texts +- **Bug Fix** Fix language server start failure in AL2023 ARM64 +- **Bug Fix** /review: Auto-review issues did not populate code issues list +- **Bug Fix** Amazon Q: Fix code upload error when using /dev or /doc on Remote SSH +- **Bug Fix** /test placeholder text aligned across IDEs +- **Bug Fix** Inline: Typos in the first example suggestion +- **Feature** Inline suggestions: Pre-fetch recommendations to reduce suggestion latency. +- **Feature** Added github issue link and description to the chat answer feedback form + ## 1.45.0 2025-01-30 - **Bug Fix** Allow AB users with an overridden customization to go back to the default customization diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 62f008a2213..6ed5ba737ec 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.46.0-SNAPSHOT", + "version": "1.46.0", "extensionKind": [ "workspace" ], From 2b345c9f9c1a64d469b573ccd2f9384a29819912 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Thu, 6 Feb 2025 18:44:51 +0000 Subject: [PATCH 02/12] Update version to snapshot version: 1.47.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/amazonq/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd775bdd02c..bd4a964f591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -23904,7 +23904,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.46.0", + "version": "1.47.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 6ed5ba737ec..deb37933ae8 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.46.0", + "version": "1.47.0-SNAPSHOT", "extensionKind": [ "workspace" ], From 610dd186585536f7c33147645650370e3d69e133 Mon Sep 17 00:00:00 2001 From: Josh Pinkney <103940141+jpinkney-aws@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:55:32 -0500 Subject: [PATCH 03/12] fix(amazonq): debugging amazon q can crash vscode (#6514) ## Problem If you have amazon q locally and start a debugging session, pressing stop can sometimes crash the entirety of vscode ## Solution remove [debugWebviews](https://github.com/microsoft/vscode-js-debug/blob/main/OPTIONS.md#rendererdebugoptions)/[rendererDebugOptions](https://github.com/microsoft/vscode-js-debug/blob/main/OPTIONS.md#rendererdebugoptions) from amazon q's launch config since they cause the local amazon q webview to attach to the debug instance which coincidentally ends up crashing vscode when extension debugging is stopped --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- packages/amazonq/.vscode/launch.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/amazonq/.vscode/launch.json b/packages/amazonq/.vscode/launch.json index 120eacdb44d..84f48b6f785 100644 --- a/packages/amazonq/.vscode/launch.json +++ b/packages/amazonq/.vscode/launch.json @@ -9,11 +9,6 @@ "name": "Extension", "type": "extensionHost", "request": "launch", - "debugWebviews": true, - "rendererDebugOptions": { - "urlFilter": "*amazonwebservices.amazon-q-vscode*", - "webRoot": "${workspaceFolder}" - }, "runtimeExecutable": "${execPath}", "args": ["--extensionDevelopmentPath=${workspaceFolder}"], "env": { From fb5baceae2b3b441910dd92d812cafd388b45b50 Mon Sep 17 00:00:00 2001 From: Vlad <44401081+witness-me@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:55:43 -0800 Subject: [PATCH 04/12] fix(lint): Remove extra space (#6517) ## Problem A line in [packages/core/package.nls.json](https://github.com/aws/aws-toolkit-vscode/compare/master...witness-me:fix-lint?expand=1#diff-4d90099a916e267c6fa8cfeeec9c569c4889dc50cb53178e1c748d0d37ff501e) contains extra space, which is inconsistent with current code style ## Solution Remove extra space --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. Co-authored-by: Vlad Nikolaenko --- packages/core/package.nls.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.nls.json b/packages/core/package.nls.json index 850f7242b45..e910c009d58 100644 --- a/packages/core/package.nls.json +++ b/packages/core/package.nls.json @@ -20,7 +20,7 @@ "AWS.configuration.description.suppressPrompts": "Prompts which ask for confirmation. Checking an item suppresses the prompt.", "AWS.configuration.enableCodeLenses": "Enable SAM hints in source code and template.yaml files", "AWS.configuration.description.resources.enabledResources": "AWS resources to display in the 'Resources' portion of the explorer.", - "AWS.configuration.description.featureDevelopment.allowRunningCodeAndTests": "Allow /dev to run code and test commands", + "AWS.configuration.description.featureDevelopment.allowRunningCodeAndTests": "Allow /dev to run code and test commands", "AWS.configuration.description.experiments": "Try experimental features and give feedback. Note that experimental features may be removed at any time.\n * `jsonResourceModification` - Enables basic create, update, and delete support for cloud resources via the JSON Resources explorer component.", "AWS.stepFunctions.asl.format.enable.desc": "Enables the default formatter used with Amazon States Language files", "AWS.stepFunctions.asl.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons).", From 02d21a2fafc7479fb398ea078aa3e3adf7c62e7a Mon Sep 17 00:00:00 2001 From: jonife <79116465+jonife@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:17:20 -0800 Subject: [PATCH 05/12] fix(appbuilder): Update support for enVar in the webview (#6413) ## Problem Update support for enVar in the webview --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- .../core/src/awsService/appBuilder/explorer/samProject.ts | 5 ++++- .../core/src/lambda/vue/configEditor/samInvokeBackend.ts | 4 ++++ .../core/src/lambda/vue/configEditor/samInvokeComponent.vue | 3 --- .../core/src/lambda/vue/configEditor/samInvokeFrontend.ts | 5 +++++ packages/core/src/test/lambda/vue/samInvokeBackend.test.ts | 3 +++ .../Feature-b2217598-82cb-4268-b731-e137fa6a92e8.json | 4 ++++ 6 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 packages/toolkit/.changes/next-release/Feature-b2217598-82cb-4268-b731-e137fa6a92e8.json diff --git a/packages/core/src/awsService/appBuilder/explorer/samProject.ts b/packages/core/src/awsService/appBuilder/explorer/samProject.ts index ce8d0c4878a..722ec323192 100644 --- a/packages/core/src/awsService/appBuilder/explorer/samProject.ts +++ b/packages/core/src/awsService/appBuilder/explorer/samProject.ts @@ -30,6 +30,9 @@ export interface ResourceTreeEntity { Events?: ResourceTreeEntity[] Path?: string Method?: string + Environment?: { + Variables: Record + } } export async function getStackName(projectRoot: vscode.Uri): Promise { @@ -81,10 +84,10 @@ function getResourceEntity(template: any): ResourceTreeEntity[] { Handler: resource.Properties?.Handler ?? template?.Globals?.Function?.Handler, Events: resource.Properties?.Events ? getEvents(resource.Properties.Events) : undefined, CodeUri: resource.Properties?.CodeUri ?? template?.Globals?.Function?.CodeUri, + Environment: resource.Properties?.Environment ?? template?.Globals?.Function?.Environment, } resourceTree.push(resourceEntity) } - return resourceTree } diff --git a/packages/core/src/lambda/vue/configEditor/samInvokeBackend.ts b/packages/core/src/lambda/vue/configEditor/samInvokeBackend.ts index ba624536b0f..2c3c8ee40dd 100644 --- a/packages/core/src/lambda/vue/configEditor/samInvokeBackend.ts +++ b/packages/core/src/lambda/vue/configEditor/samInvokeBackend.ts @@ -46,6 +46,9 @@ export interface ResourceData { runtime: string stackName: string source: string + environment?: { + Variables: Record + } } export type AwsSamDebuggerConfigurationLoose = AwsSamDebuggerConfiguration & { @@ -441,6 +444,7 @@ export async function registerSamDebugInvokeVueCommand( runtime: resource.resource.Runtime!, arn: resource.functionArn ?? '', stackName: resource.stackName ?? '', + environment: resource.resource.Environment, source: source, }) await telemetry.sam_openConfigUi.run(async (span) => { diff --git a/packages/core/src/lambda/vue/configEditor/samInvokeComponent.vue b/packages/core/src/lambda/vue/configEditor/samInvokeComponent.vue index 468d7393ac6..6d64291cff6 100644 --- a/packages/core/src/lambda/vue/configEditor/samInvokeComponent.vue +++ b/packages/core/src/lambda/vue/configEditor/samInvokeComponent.vue @@ -29,9 +29,6 @@ debugger to the code running in a local Docker container. open launch.json.

- Note: If you are accessing environment variables in your function code, ensure you - input them in the "Additional fields -> Lambda -> Environment variables" section, following JSON - format:{"KEY":"VALUE"}

diff --git a/packages/core/src/lambda/vue/configEditor/samInvokeFrontend.ts b/packages/core/src/lambda/vue/configEditor/samInvokeFrontend.ts index c266abb8a4b..6502accae41 100644 --- a/packages/core/src/lambda/vue/configEditor/samInvokeFrontend.ts +++ b/packages/core/src/lambda/vue/configEditor/samInvokeFrontend.ts @@ -345,6 +345,11 @@ export default defineComponent({ this.launchConfig.invokeTarget.lambdaHandler = this.resourceData.handler if (this.launchConfig.lambda) { this.launchConfig.lambda.runtime = this.resourceData.runtime + if (this.resourceData.environment?.Variables !== undefined) { + this.environmentVariables.value = JSON.stringify( + this.resourceData.environment?.Variables + ) + } } } }, diff --git a/packages/core/src/test/lambda/vue/samInvokeBackend.test.ts b/packages/core/src/test/lambda/vue/samInvokeBackend.test.ts index 18ae33b67d0..cbad9bfff55 100644 --- a/packages/core/src/test/lambda/vue/samInvokeBackend.test.ts +++ b/packages/core/src/test/lambda/vue/samInvokeBackend.test.ts @@ -728,6 +728,9 @@ describe('SamInvokeWebview', () => { }, lambda: { runtime: 'python3.9', + environmentVariables: { + PARAM1: 'VALUE', + }, }, sam: { containerBuild: false, diff --git a/packages/toolkit/.changes/next-release/Feature-b2217598-82cb-4268-b731-e137fa6a92e8.json b/packages/toolkit/.changes/next-release/Feature-b2217598-82cb-4268-b731-e137fa6a92e8.json new file mode 100644 index 00000000000..e96232f471c --- /dev/null +++ b/packages/toolkit/.changes/next-release/Feature-b2217598-82cb-4268-b731-e137fa6a92e8.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "Lambda: Support for environment variables in the editor webview." +} From 34dc1019b79bc1abae6515b230a174313dc012d6 Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Thu, 6 Feb 2025 19:19:55 -0400 Subject: [PATCH 06/12] fix(amazonq): log full error (#6422) ## Problem When API calls fail, it can be difficult to debug without the requestId. ## Solution Log entire error to ensure we have all relevant details, not just the error message. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani --- .../transformByQ/transformApiHandler.ts | 64 +++++++------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts index b5f4d2d1447..023e0208bf8 100644 --- a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts +++ b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts @@ -127,7 +127,9 @@ export async function uploadArtifactToS3( if (response.status === 200) { break } - throw new Error('Upload failed') + throw new Error( + `Upload failed, status = ${response.status}; full response: ${JSON.stringify(response)}` + ) } catch (e: any) { if (response && !retriableCodes.includes(response.status)) { throw new Error(`Upload failed with status code = ${response.status}; did not automatically retry`) @@ -169,7 +171,7 @@ export async function resumeTransformationJob(jobId: string, userActionStatus: T } } catch (e: any) { const errorMessage = `Resuming the job failed due to: ${(e as Error).message}` - getLogger().error(`CodeTransformation: ResumeTransformation error = ${errorMessage}`) + getLogger().error(`CodeTransformation: ResumeTransformation error = %O`, e) throw new Error(errorMessage) } } @@ -180,18 +182,12 @@ export async function stopJob(jobId: string) { } try { - const response = await codeWhisperer.codeWhispererClient.codeModernizerStopCodeTransformation({ + await codeWhisperer.codeWhispererClient.codeModernizerStopCodeTransformation({ transformationJobId: jobId, }) - if (response !== undefined) { - // always store request ID, but it will only show up in a notification if an error occurs - if (response.$response.requestId) { - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) - } - } } catch (e: any) { - const errorMessage = (e as Error).message - getLogger().error(`CodeTransformation: StopTransformation error = ${errorMessage}`) + transformByQState.setJobFailureMetadata(` (request ID: ${e.requestId ?? 'unavailable'})`) + getLogger().error(`CodeTransformation: StopTransformation error = %O`, e) throw new Error('Stop job failed') } } @@ -209,12 +205,10 @@ export async function uploadPayload(payloadFileName: string, uploadContext?: Upl uploadIntent: CodeWhispererConstants.uploadIntent, uploadContext, }) - if (response.$response.requestId) { - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) - } } catch (e: any) { - const errorMessage = `The upload failed due to: ${(e as Error).message}` - getLogger().error(`CodeTransformation: CreateUploadUrl error: = ${e}`) + const errorMessage = `Creating the upload URL failed due to: ${(e as Error).message}` + transformByQState.setJobFailureMetadata(` (request ID: ${e.requestId ?? 'unavailable'})`) + getLogger().error(`CodeTransformation: CreateUploadUrl error: = %O`, e) throw new Error(errorMessage) } @@ -449,13 +443,11 @@ export async function startJob(uploadId: string) { }, }) getLogger().info('CodeTransformation: called startJob API successfully') - if (response.$response.requestId) { - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) - } return response.transformationJobId } catch (e: any) { const errorMessage = `Starting the job failed due to: ${(e as Error).message}` - getLogger().error(`CodeTransformation: StartTransformation error = ${errorMessage}`) + transformByQState.setJobFailureMetadata(` (request ID: ${e.requestId ?? 'unavailable'})`) + getLogger().error(`CodeTransformation: StartTransformation error = %O`, e) throw new Error(errorMessage) } } @@ -573,9 +565,6 @@ export async function getTransformationPlan(jobId: string) { response = await codeWhisperer.codeWhispererClient.codeModernizerGetCodeTransformationPlan({ transformationJobId: jobId, }) - if (response.$response.requestId) { - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) - } const stepZeroProgressUpdates = response.transformationPlan.transformationSteps[0].progressUpdates @@ -618,13 +607,14 @@ export async function getTransformationPlan(jobId: string) { return plan } catch (e: any) { const errorMessage = (e as Error).message - getLogger().error(`CodeTransformation: GetTransformationPlan error = ${errorMessage}`) + transformByQState.setJobFailureMetadata(` (request ID: ${e.requestId ?? 'unavailable'})`) + getLogger().error(`CodeTransformation: GetTransformationPlan error = %O`, e) /* Means API call failed * If response is defined, means a display/parsing error occurred, so continue transformation */ if (response === undefined) { - throw new Error('Get plan API call failed') + throw new Error(errorMessage) } } } @@ -638,13 +628,10 @@ export async function getTransformationSteps(jobId: string, handleThrottleFlag: const response = await codeWhisperer.codeWhispererClient.codeModernizerGetCodeTransformationPlan({ transformationJobId: jobId, }) - if (response.$response.requestId) { - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) - } return response.transformationPlan.transformationSteps.slice(1) // skip step 0 (contains supplemental info) } catch (e: any) { - const errorMessage = (e as Error).message - getLogger().error(`CodeTransformation: GetTransformationPlan error = ${errorMessage}`) + transformByQState.setJobFailureMetadata(` (request ID: ${e.requestId ?? 'unavailable'})`) + getLogger().error(`CodeTransformation: GetTransformationPlan error = %O`, e) throw e } } @@ -682,7 +669,6 @@ export async function pollTransformationJob(jobId: string, validStates: string[] transformByQState.setJobFailureErrorNotification( `${CodeWhispererConstants.failedToCompleteJobGenericNotification} ${errorMessage}` ) - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) } if (validStates.includes(status)) { break @@ -700,14 +686,14 @@ export async function pollTransformationJob(jobId: string, validStates: string[] * is called, we break above on validStatesForCheckingDownloadUrl and check final status in finalizeTransformationJob */ if (CodeWhispererConstants.failureStates.includes(status)) { - transformByQState.setJobFailureMetadata(` (request ID: ${response.$response.requestId})`) - throw new JobStoppedError(response.$response.requestId) + throw new JobStoppedError( + response.transformationJob.reason ?? 'no failure reason in GetTransformation response' + ) } await sleep(CodeWhispererConstants.transformationJobPollingIntervalSeconds * 1000) } catch (e: any) { - let errorMessage = (e as Error).message - errorMessage += ` -- ${transformByQState.getJobFailureMetadata()}` - getLogger().error(`CodeTransformation: GetTransformation error = ${errorMessage}`) + getLogger().error(`CodeTransformation: GetTransformation error = %O`, e) + transformByQState.setJobFailureMetadata(` (request ID: ${e.requestId ?? 'unavailable'})`) throw e } } @@ -752,7 +738,6 @@ export async function downloadResultArchive( pathToArchive: string, downloadArtifactType: TransformationDownloadArtifactType ) { - let downloadErrorMessage = undefined const cwStreamingClient = await createCodeWhispererChatStreamingClient() try { @@ -765,8 +750,7 @@ export async function downloadResultArchive( pathToArchive ) } catch (e: any) { - downloadErrorMessage = (e as Error).message - getLogger().error(`CodeTransformation: ExportResultArchive error = ${downloadErrorMessage}`) + getLogger().error(`CodeTransformation: ExportResultArchive error = %O`, e) throw e } finally { cwStreamingClient.destroy() @@ -795,7 +779,7 @@ export async function downloadAndExtractResultArchive( zip.extractAllTo(pathToArchiveDir) } catch (e) { downloadErrorMessage = (e as Error).message - getLogger().error(`CodeTransformation: ExportResultArchive error = ${downloadErrorMessage}`) + getLogger().error(`CodeTransformation: ExportResultArchive error = %O`, e) throw new Error('Error downloading transformation result artifacts: ' + downloadErrorMessage) } } From 928593c32b4b510b3faa94c0d462a5e12203e6d7 Mon Sep 17 00:00:00 2001 From: Hweinstock <42325418+Hweinstock@users.noreply.github.com> Date: Fri, 7 Feb 2025 08:24:15 -0500 Subject: [PATCH 07/12] refactor(debounce): avoid reimplementations of the same logic. (#6507) ## Problem `debounce` is reimplemented in multiple places. There is `debounce`: https://github.com/aws/aws-toolkit-vscode/blob/100eb0737789d9d5ba4b04e055730b467bd97e14/packages/core/src/shared/utilities/functionUtils.ts#L89-L108 `cancellableDebounce`: https://github.com/aws/aws-toolkit-vscode/blob/100eb0737789d9d5ba4b04e055730b467bd97e14/packages/core/src/shared/utilities/functionUtils.ts#L114-L147 and a very similar function `keyedDebounce`: https://github.com/aws/aws-toolkit-vscode/blob/100eb0737789d9d5ba4b04e055730b467bd97e14/packages/core/src/auth/auth.ts#L107-L122 These functions should share common implementation logic, and live in the same place for easier discoverability. ## Solution - reimplement `debounce` in terms of `cancellableDebounce` since its a special case. - move these functions to shared, common location. - augment `debounce` to allow the callback to take arguments. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- packages/core/src/auth/auth.ts | 19 +----- .../src/shared/utilities/functionUtils.ts | 65 +++++++++++-------- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/packages/core/src/auth/auth.ts b/packages/core/src/auth/auth.ts index bfe2090268f..fba0c80e261 100644 --- a/packages/core/src/auth/auth.ts +++ b/packages/core/src/auth/auth.ts @@ -21,7 +21,7 @@ import { SsoClient } from './sso/clients' import { getLogger } from '../shared/logger' import { CredentialsProviderManager } from './providers/credentialsProviderManager' import { asString, CredentialsId, CredentialsProvider, fromString } from './providers/credentials' -import { once } from '../shared/utilities/functionUtils' +import { keyedDebounce, once } from '../shared/utilities/functionUtils' import { CredentialsSettings } from './credentials/utils' import { extractDataFromSection, @@ -104,23 +104,6 @@ interface AuthService { updateConnection(connection: Pick, profile: Profile): Promise } -function keyedDebounce( - fn: (key: K, ...args: U) => Promise -): typeof fn { - const pending = new Map>() - - return (key, ...args) => { - if (pending.has(key)) { - return pending.get(key)! - } - - const promise = fn(key, ...args).finally(() => pending.delete(key)) - pending.set(key, promise) - - return promise - } -} - export interface ConnectionStateChangeEvent { readonly id: Connection['id'] readonly state: ProfileMetadata['connectionState'] diff --git a/packages/core/src/shared/utilities/functionUtils.ts b/packages/core/src/shared/utilities/functionUtils.ts index d21727bac1d..3bcb87730fa 100644 --- a/packages/core/src/shared/utilities/functionUtils.ts +++ b/packages/core/src/shared/utilities/functionUtils.ts @@ -85,38 +85,28 @@ export function memoize(fn: (...args: U) => T): (...args: U) * Multiple calls made during the debounce window will receive references to the * same Promise similar to {@link shared}. The window will also be 'rolled', delaying * the execution by another {@link delay} milliseconds. + * + * This function prevents execution until {@link delay} milliseconds have passed + * since the last invocation regardless of arguments. If this should be + * argument dependent, look into {@link keyedDebounce} */ -export function debounce(cb: () => T | Promise, delay: number = 0): () => Promise { - let timeout: Timeout | undefined - let promise: Promise | undefined - - return () => { - timeout?.refresh() - - return (promise ??= new Promise((resolve, reject) => { - timeout = new Timeout(delay) - timeout.onCompletion(async () => { - timeout = promise = undefined - try { - resolve(await cb()) - } catch (err) { - reject(err) - } - }) - })) - } +export function debounce( + cb: (...args: Input) => Output | Promise, + delay: number = 0 +): (...args: Input) => Promise { + return cancellableDebounce(cb, delay).promise } /** * - * Similar to {@link debounce}, but allows the function to be cancelled and allow callbacks to pass function parameters. + * Similar to {@link debounce}, but allows the function to be cancelled. */ -export function cancellableDebounce( - cb: (...args: U) => T | Promise, +export function cancellableDebounce( + cb: (...args: Input) => Output | Promise, delay: number = 0 -): { promise: (...args: U) => Promise; cancel: () => void } { +): { promise: (...args: Input) => Promise; cancel: () => void } { let timeout: Timeout | undefined - let promise: Promise | undefined + let promise: Promise | undefined const cancel = (): void => { if (timeout) { @@ -127,15 +117,15 @@ export function cancellableDebounce( } return { - promise: (...arg) => { + promise: (...args: Input) => { timeout?.refresh() - return (promise ??= new Promise((resolve, reject) => { + return (promise ??= new Promise((resolve, reject) => { timeout = new Timeout(delay) timeout.onCompletion(async () => { timeout = promise = undefined try { - resolve(await cb(...arg)) + resolve(await cb(...args)) } catch (err) { reject(err) } @@ -145,3 +135,24 @@ export function cancellableDebounce( cancel: cancel, } } + +/** + * + * Similar to {@link debounce}, but uses a key to determine if the function should be called yet rather than a timeout connected to the function itself. + */ +export function keyedDebounce( + fn: (key: K, ...args: U) => Promise +): typeof fn { + const pending = new Map>() + + return (key, ...args) => { + if (pending.has(key)) { + return pending.get(key)! + } + + const promise = fn(key, ...args).finally(() => pending.delete(key)) + pending.set(key, promise) + + return promise + } +} From 353aa2739b2c10d521a0f9a88eee518bbfb3be20 Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Fri, 7 Feb 2025 12:28:04 -0500 Subject: [PATCH 08/12] fix(auth): token refresh rapidly called unexpectedly (#6479) ## Problem: getChatAuthState() is called in many places by the Q features simultaneously, this eventually triggers multiple calls to getToken() and if needed refreshToken(). This resulted in refreshToken being spammed and the Identity team seeing spikes in token refreshes from clients. ## Solution: Throttle getChatAuthState(). Throttling w/ leading: true, allows us to instantly return a fresh result OR a cached result in the case we are throttled. Debounce on the other hand would cause callers to hang since they have to wait for debounce to timeout. Also, we put a debounce on getToken() before in #6282 but this did not work since a new SsoAccessToken instance is created each time the offending code flow triggered (we could look to cache the instance instead which would enable the getToken() debounce to be useful. ### Testing To test the difference after adding the throttle: - Add log statements to `getToken()` - Set an expired date in the SSO cache for both token expiration + client registration expiration - Use chat What would happen is that without throttle it would trigger getChatAuthState() many times, likely due to the connection becoming invalid and sending an event to all Q features, causing each of them to call getChatAuthState() at the same time. But when the throttle was added, the amount of these calls dropped to at most 2. Signed-off-by: nkomonen-amazon --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Signed-off-by: nkomonen-amazon --- packages/amazonq/src/extensionNode.ts | 2 +- .../core/src/auth/sso/ssoAccessTokenProvider.ts | 15 +-------------- .../core/src/codewhisperer/util/authUtil.ts | 17 ++++++++++++++++- .../sso/ssoAccessTokenProvider.test.ts | 14 -------------- 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/packages/amazonq/src/extensionNode.ts b/packages/amazonq/src/extensionNode.ts index 6fe0c28ad8f..04ca8c4023f 100644 --- a/packages/amazonq/src/extensionNode.ts +++ b/packages/amazonq/src/extensionNode.ts @@ -82,7 +82,7 @@ async function getAuthState(): Promise> { try { // May call connection validate functions that try to refresh the token. // This could result in network errors. - authState = (await AuthUtil.instance.getChatAuthState(false)).codewhispererChat + authState = (await AuthUtil.instance._getChatAuthState(false)).codewhispererChat } catch (err) { if ( isNetworkError(err) && diff --git a/packages/core/src/auth/sso/ssoAccessTokenProvider.ts b/packages/core/src/auth/sso/ssoAccessTokenProvider.ts index d0c8af56c3f..6639e9f3832 100644 --- a/packages/core/src/auth/sso/ssoAccessTokenProvider.ts +++ b/packages/core/src/auth/sso/ssoAccessTokenProvider.ts @@ -33,7 +33,7 @@ import { randomUUID } from '../../shared/crypto' import { getExtRuntimeContext } from '../../shared/vscode/env' import { showInputBox } from '../../shared/ui/inputPrompter' import { AmazonQPromptSettings, DevSettings, PromptSettings, ToolkitPromptSettings } from '../../shared/settings' -import { debounce, onceChanged } from '../../shared/utilities/functionUtils' +import { onceChanged } from '../../shared/utilities/functionUtils' import { NestedMap } from '../../shared/utilities/map' import { asStringifiedStack } from '../../shared/telemetry/spans' import { showViewLogsMessage } from '../../shared/utilities/messages' @@ -97,20 +97,7 @@ export abstract class SsoAccessTokenProvider { this.reAuthState.set(this.profile, { reAuthReason: `invalidate():${reason}` }) } - /** - * Sometimes we get many calls at once and this - * can trigger redundant disk reads, or token refreshes. - * We debounce to avoid this. - * - * NOTE: The property {@link getTokenDebounced()} does not work with being stubbed for tests, so - * this redundant function was created to work around that. - */ public async getToken(): Promise { - return this.getTokenDebounced() - } - private getTokenDebounced = debounce(() => this._getToken(), 50) - /** Exposed for testing purposes only */ - public async _getToken(): Promise { const data = await this.cache.token.load(this.tokenCacheKey) SsoAccessTokenProvider.logIfChanged( indent( diff --git a/packages/core/src/codewhisperer/util/authUtil.ts b/packages/core/src/codewhisperer/util/authUtil.ts index a9045220ea2..1a94ad5ffcc 100644 --- a/packages/core/src/codewhisperer/util/authUtil.ts +++ b/packages/core/src/codewhisperer/util/authUtil.ts @@ -44,6 +44,7 @@ import { telemetry } from '../../shared/telemetry/telemetry' import { asStringifiedStack } from '../../shared/telemetry/spans' import { withTelemetryContext } from '../../shared/telemetry/util' import { focusAmazonQPanel } from '../../codewhispererChat/commands/registerCommands' +import { throttle } from 'lodash' /** Backwards compatibility for connections w pre-chat scopes */ export const codeWhispererCoreScopes = [...scopesCodeWhispererCore] @@ -402,9 +403,23 @@ export class AuthUtil { * * By default, network errors are ignored when determining auth state since they may be silently * recoverable later. + * + * THROTTLE: This function is called in rapid succession by Amazon Q features and can lead to + * a barrage of disk access and/or token refreshes. We throttle to deal with this. + * + * Note we do an explicit cast of the return type due to Lodash types incorrectly indicating + * a FeatureAuthState or undefined can be returned. But since we set `leading: true` + * it will always return FeatureAuthState + */ + public getChatAuthState = throttle(() => this._getChatAuthState(), 2000, { + leading: true, + }) as () => Promise + /** + * IMPORTANT: Only use this if you do NOT want to swallow network errors, otherwise use {@link getChatAuthState()} + * @param ignoreNetErr swallows network errors */ @withTelemetryContext({ name: 'getChatAuthState', class: authClassName }) - public async getChatAuthState(ignoreNetErr: boolean = true): Promise { + public async _getChatAuthState(ignoreNetErr: boolean = true): Promise { // The state of the connection may not have been properly validated // and the current state we see may be stale, so refresh for latest state. if (ignoreNetErr) { diff --git a/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts b/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts index 6536095cd59..2cb98193224 100644 --- a/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts +++ b/packages/core/src/test/credentials/sso/ssoAccessTokenProvider.test.ts @@ -156,20 +156,6 @@ describe('SsoAccessTokenProvider', function () { assert.strictEqual(cachedToken, undefined) }) - it('concurrent calls are debounced', async function () { - const validToken = createToken(hourInMs) - await cache.token.save(startUrl, { region, startUrl, token: validToken }) - const actualGetToken = sinon.spy(sut, '_getToken') - - const result = await Promise.all([sut.getToken(), sut.getToken(), sut.getToken()]) - - // Subsequent other calls were debounced so this was only called once - assert.strictEqual(actualGetToken.callCount, 1) - for (const r of result) { - assert.deepStrictEqual(r, validToken) - } - }) - describe('Exceptions', function () { it('drops expired tokens if failure was a client-fault', async function () { const exception = new UnauthorizedClientException({ message: '', $metadata: {} }) From fb26635aa77e68aaf0d0faecfe33eb9c784811cb Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Fri, 7 Feb 2025 15:38:32 -0400 Subject: [PATCH 09/12] feat(amazonq): java21 support (#6414) ## Problem Support transformations to Java 21. ## Solution Add support. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani Co-authored-by: Maxim Hayes <149123719+hayemaxi@users.noreply.github.com> --- ...-f0b1a42d-ee00-4b68-9160-cbae9bd27873.json | 4 +++ .../test/e2e/amazonq/transformByQ.test.ts | 36 +++++++++++++++++++ .../chat/controller/controller.ts | 6 ++++ .../chat/controller/messenger/messenger.ts | 16 ++++++++- .../controller/messenger/messengerUtils.ts | 2 ++ .../commands/startTransformByQ.ts | 2 ++ .../src/codewhisperer/models/constants.ts | 19 ++++++---- .../core/src/codewhisperer/models/model.ts | 5 +-- .../transformByQ/transformApiHandler.ts | 2 +- 9 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Feature-f0b1a42d-ee00-4b68-9160-cbae9bd27873.json diff --git a/packages/amazonq/.changes/next-release/Feature-f0b1a42d-ee00-4b68-9160-cbae9bd27873.json b/packages/amazonq/.changes/next-release/Feature-f0b1a42d-ee00-4b68-9160-cbae9bd27873.json new file mode 100644 index 00000000000..9361a52e434 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Feature-f0b1a42d-ee00-4b68-9160-cbae9bd27873.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "/transform: support Java 21 transformations" +} diff --git a/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts b/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts index b28368e1e7f..4f3db30cb24 100644 --- a/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts +++ b/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts @@ -181,6 +181,42 @@ describe('Amazon Q Code Transformation', function () { assert.strictEqual(viewSummaryChatItem?.body?.includes('view a summary'), true) }) + it('CANNOT do a Java 21 to Java 17 transformation', async () => { + sinon.stub(startTransformByQ, 'getValidSQLConversionCandidateProjects').resolves([]) + sinon.stub(GumbyController.prototype, 'validateLanguageUpgradeProjects' as keyof GumbyController).resolves([ + { + name: 'qct-sample-java-8-app-main', + path: '/Users/alias/Desktop/qct-sample-java-8-app-main', + JDKVersion: JDKVersion.JDK21, + }, + ]) + tab.addChatMessage({ command: '/transform' }) + await tab.waitForEvent(() => tab.getChatItems().length > 3, { + waitTimeoutInMs: 5000, + waitIntervalInMs: 1000, + }) + const projectForm = tab.getChatItems().pop() + assert.strictEqual(projectForm?.formItems?.[0]?.id ?? undefined, 'GumbyTransformLanguageUpgradeProjectForm') + + const projectFormItemValues = { + GumbyTransformLanguageUpgradeProjectForm: '/Users/alias/Desktop/qct-sample-java-8-app-main', + GumbyTransformJdkFromForm: '21', + GumbyTransformJdkToForm: '17', + } + const projectFormValues: Record = { ...projectFormItemValues } + tab.clickCustomFormButton({ + id: 'gumbyLanguageUpgradeTransformFormConfirm', + text: 'Confirm', + formItemValues: projectFormValues, + }) + await tab.waitForEvent(() => tab.getChatItems().length > 4, { + waitTimeoutInMs: 5000, + waitIntervalInMs: 1000, + }) + const errorMessage = tab.getChatItems().pop() + assert.strictEqual(errorMessage?.body, CodeWhispererConstants.invalidFromToJdkChatMessage) + }) + it('Can provide metadata file for a SQL conversion', async () => { sinon.stub(startTransformByQ, 'getValidSQLConversionCandidateProjects').resolves([ { diff --git a/packages/core/src/amazonqGumby/chat/controller/controller.ts b/packages/core/src/amazonqGumby/chat/controller/controller.ts index 647c5682184..8fb73fbd4fc 100644 --- a/packages/core/src/amazonqGumby/chat/controller/controller.ts +++ b/packages/core/src/amazonqGumby/chat/controller/controller.ts @@ -483,6 +483,12 @@ export class GumbyController { message.tabID ) + // do not allow downgrades (only this combination can be selected in the UI) + if (fromJDKVersion === JDKVersion.JDK21 && toJDKVersion === JDKVersion.JDK17) { + this.messenger.sendUnrecoverableErrorResponse('invalid-from-to-jdk', message.tabID) + return + } + await processLanguageUpgradeTransformFormInput(pathToProject, fromJDKVersion, toJDKVersion) await this.messenger.sendSkipTestsPrompt(message.tabID) }) diff --git a/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts b/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts index a586756cb61..a31e8423231 100644 --- a/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts +++ b/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts @@ -51,6 +51,7 @@ export type UnrecoverableErrorType = | 'unsupported-target-db' | 'error-parsing-sct-file' | 'invalid-zip-no-sct-file' + | 'invalid-from-to-jdk' export enum GumbyNamedMessages { COMPILATION_PROGRESS_MESSAGE = 'gumbyProjectCompilationMessage', @@ -176,7 +177,9 @@ export class Messenger { this.dispatcher.sendAsyncEventProgress( new AsyncEventProgressMessage(tabID, { inProgress: true, - message: CodeWhispererConstants.userPatchDescriptionChatMessage, + message: CodeWhispererConstants.userPatchDescriptionChatMessage( + transformByQState.getTargetJDKVersion() ?? '' + ), }) ) @@ -233,6 +236,10 @@ export class Messenger { value: JDKVersion.JDK17, label: JDKVersion.JDK17, }, + { + value: JDKVersion.JDK21, + label: JDKVersion.JDK21, + }, ], }) @@ -246,6 +253,10 @@ export class Messenger { value: JDKVersion.JDK17, label: JDKVersion.JDK17, }, + { + value: JDKVersion.JDK21, + label: JDKVersion.JDK21, + }, ], }) @@ -481,6 +492,9 @@ export class Messenger { case 'invalid-zip-no-sct-file': message = CodeWhispererConstants.invalidMetadataFileNoSctFile break + case 'invalid-from-to-jdk': + message = CodeWhispererConstants.invalidFromToJdkChatMessage + break } this.sendJobFinishedMessage(tabID, message) diff --git a/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts b/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts index 3d3c18959d3..2cfbfc4dc4a 100644 --- a/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts +++ b/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts @@ -52,6 +52,8 @@ export default class MessengerUtils { javaHomePrompt += ` ${CodeWhispererConstants.macJavaVersionHomeHelpChatMessage(11)}` } else if (jdkVersion === JDKVersion.JDK17) { javaHomePrompt += ` ${CodeWhispererConstants.macJavaVersionHomeHelpChatMessage(17)}` + } else if (jdkVersion === JDKVersion.JDK21) { + javaHomePrompt += ` ${CodeWhispererConstants.macJavaVersionHomeHelpChatMessage(21)}` } } else { javaHomePrompt += ` ${CodeWhispererConstants.linuxJavaHomeHelpChatMessage}` diff --git a/packages/core/src/codewhisperer/commands/startTransformByQ.ts b/packages/core/src/codewhisperer/commands/startTransformByQ.ts index 154b8c07dcf..50be99b7fcf 100644 --- a/packages/core/src/codewhisperer/commands/startTransformByQ.ts +++ b/packages/core/src/codewhisperer/commands/startTransformByQ.ts @@ -119,6 +119,8 @@ async function validateJavaHome(): Promise { javaVersionUsedByMaven = JDKVersion.JDK11 } else if (javaVersionUsedByMaven === '17.') { javaVersionUsedByMaven = JDKVersion.JDK17 + } else if (javaVersionUsedByMaven === '21.') { + javaVersionUsedByMaven = JDKVersion.JDK21 } } if (javaVersionUsedByMaven !== transformByQState.getSourceJDKVersion()) { diff --git a/packages/core/src/codewhisperer/models/constants.ts b/packages/core/src/codewhisperer/models/constants.ts index f0ff34dcb02..f4e3787f6a7 100644 --- a/packages/core/src/codewhisperer/models/constants.ts +++ b/packages/core/src/codewhisperer/models/constants.ts @@ -24,7 +24,9 @@ export const AWSTemplateCaseInsensitiveKeyWords = ['cloudformation', 'cfn', 'tem const patchDescriptions: { [key: string]: string } = { 'Prepare minimal upgrade to Java 17': - 'This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks.', + 'This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks in Java 17.', + 'Prepare minimal upgrade to Java 21': + 'This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks in Java 21.', 'Popular Enterprise Specifications and Application Frameworks upgrade': 'This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.', 'HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks': @@ -505,14 +507,14 @@ export const codeTransformLocThreshold = 100000 export const jobStartedChatMessage = 'I am starting to transform your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your project. To monitor progress, go to the Transformation Hub. If I run into any issues, I might pause the transformation to get input from you on how to proceed.' -export const chooseTransformationObjective = `I can help you with the following tasks:\n- Upgrade your Java 8 and Java 11 codebases to Java 17, or upgrade Java 17 code with up to date libraries and other dependencies.\n- Convert embedded SQL code for Oracle to PostgreSQL database migrations in AWS DMS. [Learn more](https://docs.aws.amazon.com/dms/latest/userguide/schema-conversion-embedded-sql.html).\n\nWhat would you like to do? You can enter "language upgrade" or "sql conversion".` +export const chooseTransformationObjective = `I can help you with the following tasks:\n- Upgrade your Java 8, Java 11, and Java 17 codebases to Java 17 or Java 21.\n- Upgrade Java 17 or Java 21 code with up-to-date libraries and other dependencies.\n- Convert embedded SQL code for Oracle to PostgreSQL database migrations in AWS DMS. [Learn more](https://docs.aws.amazon.com/dms/latest/userguide/schema-conversion-embedded-sql.html).\n\nWhat would you like to do? You can enter "language upgrade" or "sql conversion".` export const chooseTransformationObjectivePlaceholder = 'Enter "language upgrade" or "sql conversion"' -export const userPatchDescriptionChatMessage = ` +export const userPatchDescriptionChatMessage = (version: string) => ` If you'd like to update and test your code with fewer changes at a time, I can divide the transformation results into separate diff patches. If applicable to your application, I can split up the diffs up into the following groups of upgrades. Here are the upgrades included in each diff: -• Minimal Compatible Library Upgrade to Java 17: Dependencies to the minimum compatible versions in Java 17, including Springboot, JUnit, and PowerMockito. +• Minimal Compatible Library Upgrade to Java ${version}: Dependencies to the minimum compatible versions in Java ${version}, including Springboot, JUnit, and PowerMockito. • Popular Enterprise Specifications Application Frameworks: Popular enterprise and application frameworks like Jakarta EE, Hibernate, and Micronaut 3. @@ -597,6 +599,9 @@ export const invalidMetadataFileErrorParsing = export const invalidMetadataFileNoSctFile = "An .sct file is required for transformation. Make sure that you've uploaded the .zip file you retrieved from your schema conversion in AWS DMS." +export const invalidFromToJdkChatMessage = + "I can't transform a project from Java 21 to Java 17, but I can upgrade Java 21 code with up to date libraries and other dependencies. Try again with a supported language upgrade." + export const sqlMetadataFileReceived = 'I found the following source database, target database, and host based on the schema conversion metadata you provided:' @@ -669,7 +674,7 @@ export const noPomXmlFoundChatMessage = `I couldn\'t find a project that I can u export const noJavaHomeFoundChatMessage = `Sorry, I couldn\'t locate your Java installation. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` export const dependencyVersionsErrorMessage = - 'I could not find any other versions of this dependency in your local Maven repository. Try transforming the dependency to make it compatible with Java 17, and then try transforming this module again.' + 'I could not find any other versions of this dependency in your local Maven repository. Try transforming the dependency to make it compatible with your target Java version, and then try transforming this module again.' export const errorUploadingWithExpiredUrl = `The upload error may have been caused by the expiration of the S3 pre-signed URL that was used to upload code artifacts to Q Code Transformation. The S3 pre-signed URL expires in 30 minutes. This could be caused by any delays introduced by intermediate services in your network infrastructure. Please investigate your network configuration and consider allowlisting 'amazonq-code-transformation-us-east-1-c6160f047e0.s3.amazonaws.com' to skip any reviewing that might delay the upload. For more information, see the [Amazon Q documentation](${codeTransformTroubleshootAllowS3Access}).` @@ -719,7 +724,7 @@ export const changesAppliedNotificationMultipleDiffs = (currentPatchIndex: numbe } } -export const noOpenProjectsFoundChatMessage = `I couldn\'t find a project that I can upgrade. Currently, I support Java 8, Java 11, and Java 17 projects built on Maven. Make sure your project is open in the IDE. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` +export const noOpenProjectsFoundChatMessage = `I couldn\'t find a project that I can upgrade. Currently, I support Java 8, Java 11, Java 17, and Java 21 projects built on Maven. Make sure your project is open in the IDE. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` export const noOpenFileFoundChatMessage = `Sorry, there isn't a source file open right now that I can generate a test for. Make sure you open a source file so I can generate tests.` @@ -731,7 +736,7 @@ export const unitTestGenerationCancelMessage = 'Unit test generation cancelled.' export const tooManyRequestErrorMessage = 'Too many requests. Please wait before retrying.' -export const noJavaProjectsFoundChatMessage = `I couldn\'t find a project that I can upgrade. Currently, I support Java 8, Java 11, and Java 17 projects built on Maven. Make sure your project is open in the IDE. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` +export const noJavaProjectsFoundChatMessage = `I couldn\'t find a project that I can upgrade. Currently, I support Java 8, Java 11, Java 17, and Java 21 projects built on Maven. Make sure your project is open in the IDE. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` export const linkToDocsHome = 'https://docs.aws.amazon.com/amazonq/latest/aws-builder-use-ug/code-transformation.html' diff --git a/packages/core/src/codewhisperer/models/model.ts b/packages/core/src/codewhisperer/models/model.ts index 0f285f04ba8..f7d1fe60f1b 100644 --- a/packages/core/src/codewhisperer/models/model.ts +++ b/packages/core/src/codewhisperer/models/model.ts @@ -649,6 +649,7 @@ export enum JDKVersion { JDK8 = '8', JDK11 = '11', JDK17 = '17', + JDK21 = '21', UNSUPPORTED = 'UNSUPPORTED', } @@ -740,7 +741,7 @@ export class TransformByQState { private sourceJDKVersion: JDKVersion | undefined = undefined - private targetJDKVersion: JDKVersion = JDKVersion.JDK17 + private targetJDKVersion: JDKVersion | undefined = undefined private produceMultipleDiffs: boolean = false @@ -1132,7 +1133,7 @@ export class TransformByQState { this.payloadFilePath = '' this.metadataPathSQL = '' this.sourceJDKVersion = undefined - this.targetJDKVersion = JDKVersion.JDK17 + this.targetJDKVersion = undefined this.sourceDB = undefined this.targetDB = undefined this.sourceServerName = '' diff --git a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts index 023e0208bf8..e35f7646bfc 100644 --- a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts +++ b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts @@ -439,7 +439,7 @@ export async function startJob(uploadId: string) { transformationSpec: { transformationType: CodeWhispererConstants.transformationType, // shared b/w language upgrades & sql conversions for now source: { language: sourceLanguageVersion }, // dummy value of JDK8 used for SQL conversions just so that this API can be called - target: { language: targetLanguageVersion }, // always JDK17 + target: { language: targetLanguageVersion }, // JAVA_17 or JAVA_21 }, }) getLogger().info('CodeTransformation: called startJob API successfully') From 67f053c19b7d8703c1dc4989a853bc4cc44e3919 Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Fri, 7 Feb 2025 15:51:18 -0400 Subject: [PATCH 10/12] fix(amazonq): remove requestId param #6524 ## Problem 1) we already have logic to show the user the request ID of the last failed API call 2) we also already have logic to show them the failure reason 3) when a job is stopped, we don't expect anything to be present in the `reason` field ## Solution Remove param --- packages/core/src/amazonqGumby/errors.ts | 2 +- .../codewhisperer/service/transformByQ/transformApiHandler.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/core/src/amazonqGumby/errors.ts b/packages/core/src/amazonqGumby/errors.ts index 42d62495477..d6805159569 100644 --- a/packages/core/src/amazonqGumby/errors.ts +++ b/packages/core/src/amazonqGumby/errors.ts @@ -43,7 +43,7 @@ export class AlternateDependencyVersionsNotFoundError extends Error { } export class JobStoppedError extends Error { - constructor(readonly requestId: string) { + constructor() { super('Job was rejected, stopped, or failed') } } diff --git a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts index e35f7646bfc..b24db799b3a 100644 --- a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts +++ b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts @@ -686,9 +686,7 @@ export async function pollTransformationJob(jobId: string, validStates: string[] * is called, we break above on validStatesForCheckingDownloadUrl and check final status in finalizeTransformationJob */ if (CodeWhispererConstants.failureStates.includes(status)) { - throw new JobStoppedError( - response.transformationJob.reason ?? 'no failure reason in GetTransformation response' - ) + throw new JobStoppedError() } await sleep(CodeWhispererConstants.transformationJobPollingIntervalSeconds * 1000) } catch (e: any) { From 19d0346db98d45480f9909629b50daf31cba1186 Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Fri, 7 Feb 2025 17:19:01 -0500 Subject: [PATCH 11/12] fix(amazonq): right click options dont send context if chat not loaded (#6527) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem: When a user starts up VSC, hasn't opened Q chat yet, then highlights text and does a right click option like "send to prompt" THEN the whole prompt fails to make it to chat. This is because there is a race condition between the message being sent to the webview, and the webview completed loading and ready to recieve messages. ## Solution: In the appToMessage publisher, verify that the chat is ready to recieve messages based on if the webview sent the chat ui ready message. Otherwise wait until we get it, and then send the message. ### Demo #### Before https://github.com/user-attachments/assets/baf86737-4a5a-4f80-86fb-9abca2c56827 #### After  https://github.com/user-attachments/assets/c3361403-5dae-49df-a878-94722eb4fc62 --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Signed-off-by: nkomonen-amazon --- ...-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json | 4 ++ packages/core/src/amazonq/apps/initContext.ts | 8 ++-- .../src/amazonq/messages/messagePublisher.ts | 45 +++++++++++++++++++ .../webview/messages/messageDispatcher.ts | 3 +- packages/core/src/shared/logger/logger.ts | 2 +- 5 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json b/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json new file mode 100644 index 00000000000..01d6ec7c8b0 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "`Send to prompt` and other context menu options not sent if chat was closed" +} diff --git a/packages/core/src/amazonq/apps/initContext.ts b/packages/core/src/amazonq/apps/initContext.ts index e33fafca7c3..f8b06e4b46a 100644 --- a/packages/core/src/amazonq/apps/initContext.ts +++ b/packages/core/src/amazonq/apps/initContext.ts @@ -4,20 +4,20 @@ */ import { EventEmitter } from 'vscode' -import { MessagePublisher } from '../messages/messagePublisher' +import { MessagePublisher, UiMessagePublisher } from '../messages/messagePublisher' import { MessageListener } from '../messages/messageListener' import { TabType } from '../webview/ui/storages/tabsStorage' export interface AmazonQAppInitContext { registerWebViewToAppMessagePublisher(eventEmitter: MessagePublisher, tabType: TabType): void - getAppsToWebViewMessagePublisher(): MessagePublisher + getAppsToWebViewMessagePublisher(): UiMessagePublisher onDidChangeAmazonQVisibility: EventEmitter } export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext { private readonly appsToWebViewEventEmitter = new EventEmitter() private readonly appsToWebViewMessageListener = new MessageListener(this.appsToWebViewEventEmitter) - private readonly appsToWebViewMessagePublisher = new MessagePublisher(this.appsToWebViewEventEmitter) + private readonly appsToWebViewMessagePublisher = new UiMessagePublisher(this.appsToWebViewEventEmitter) private readonly webViewToAppsMessagePublishers: Map> = new Map() public readonly onDidChangeAmazonQVisibility = new EventEmitter() @@ -41,7 +41,7 @@ export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext { return this.appsToWebViewMessageListener } - getAppsToWebViewMessagePublisher(): MessagePublisher { + getAppsToWebViewMessagePublisher(): UiMessagePublisher { return this.appsToWebViewMessagePublisher } } diff --git a/packages/core/src/amazonq/messages/messagePublisher.ts b/packages/core/src/amazonq/messages/messagePublisher.ts index d2987a99536..7fa6976b9a9 100644 --- a/packages/core/src/amazonq/messages/messagePublisher.ts +++ b/packages/core/src/amazonq/messages/messagePublisher.ts @@ -12,3 +12,48 @@ export class MessagePublisher { this.eventEmitter.fire(event) } } + +/** + * Same as {@link MessagePublisher}, but will wait until the UI indicates it + * is ready to recieve messages, before the message is published. + * + * This solves a problem when running a right click menu option like + * "Send To Prompt" BUT chat is not opened yet, it would result in the prompt failing to + * be recieved by chat. + */ +export class UiMessagePublisher extends MessagePublisher { + private isUiReady: boolean = false + private buffer: T[] = [] + + constructor(eventEmitter: EventEmitter) { + super(eventEmitter) + } + + public override publish(event: T): void { + // immediately send if Chat UI is ready + if (this.isUiReady) { + super.publish(event) + return + } + + this.buffer.push(event) + } + + /** + * Indicate the Q Chat UI is ready to recieve messages. + */ + public setUiReady() { + this.isUiReady = true + this.flush() + } + + /** + * Publishes all blocked messages + */ + private flush() { + for (const msg of this.buffer) { + super.publish(msg) + } + this.buffer = [] + } +} diff --git a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts index 8acd04e8953..fdd1584b767 100644 --- a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts +++ b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts @@ -13,6 +13,7 @@ import { telemetry } from '../../../shared/telemetry' import { AmazonQChatMessageDuration } from '../../messages/chatMessageDuration' import { globals, openUrl } from '../../../shared' import { isClickTelemetry, isOpenAgentTelemetry } from '../ui/telemetry/actions' +import { DefaultAmazonQAppInitContext } from '../../apps/initContext' export function dispatchWebViewMessagesToApps( webview: Webview, @@ -21,12 +22,12 @@ export function dispatchWebViewMessagesToApps( webview.onDidReceiveMessage((msg) => { switch (msg.command) { case 'ui-is-ready': { + DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().setUiReady() /** * ui-is-ready isn't associated to any tab so just record the telemetry event and continue. * This would be equivalent of the duration between "user clicked open q" and "ui has become available" * NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview. */ - telemetry.webview_load.emit({ webviewName: 'amazonq', duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration, diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index d5bf5f13380..19be5ac2887 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode' -export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown' +export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown' | 'chat' class ErrorLog { constructor( From 750770ff4e0d68930d89a0a5751ad51cb0ddafa4 Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Fri, 7 Feb 2025 17:21:13 -0500 Subject: [PATCH 12/12] feat(amazonq): auto-download results (#6519) ## Problem Transformation results/artifacts expire after 24h, and sometimes users forget to manually click the "Download Proposed Changes" button within that time period. ## Solution Auto-download the results from S3 when ready. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani --- .../Feature-d9128dff-2867-4bf4-9046-2a52a36803d7.json | 4 ++++ .../core/src/codewhisperer/commands/startTransformByQ.ts | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 packages/amazonq/.changes/next-release/Feature-d9128dff-2867-4bf4-9046-2a52a36803d7.json diff --git a/packages/amazonq/.changes/next-release/Feature-d9128dff-2867-4bf4-9046-2a52a36803d7.json b/packages/amazonq/.changes/next-release/Feature-d9128dff-2867-4bf4-9046-2a52a36803d7.json new file mode 100644 index 00000000000..add00c79b5e --- /dev/null +++ b/packages/amazonq/.changes/next-release/Feature-d9128dff-2867-4bf4-9046-2a52a36803d7.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "/transform: automatically download results when ready" +} diff --git a/packages/core/src/codewhisperer/commands/startTransformByQ.ts b/packages/core/src/codewhisperer/commands/startTransformByQ.ts index 50be99b7fcf..cec513d4f58 100644 --- a/packages/core/src/codewhisperer/commands/startTransformByQ.ts +++ b/packages/core/src/codewhisperer/commands/startTransformByQ.ts @@ -775,6 +775,12 @@ export async function postTransformationJob() { if (transformByQState.getPayloadFilePath() !== '') { fs.rmSync(transformByQState.getPayloadFilePath(), { recursive: true, force: true }) // delete ZIP if it exists } + + // attempt download for user + // TODO: refactor as explained here https://github.com/aws/aws-toolkit-vscode/pull/6519/files#r1946873107 + if (transformByQState.isSucceeded() || transformByQState.isPartiallySucceeded()) { + await vscode.commands.executeCommand('aws.amazonq.transformationHub.reviewChanges.startReview') + } } export async function transformationJobErrorHandler(error: any) {