Skip to content

Commit 523ed18

Browse files
authored
Merge pull request #6537 from aws/autoMerge/feature/stepfunctions-workflow
Merge master into feature/stepfunctions-workflow
2 parents 9f53cb2 + 3f503ef commit 523ed18

File tree

20 files changed

+328
-72
lines changed

20 files changed

+328
-72
lines changed

CONTRIBUTING.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -368,31 +368,28 @@ The `aws.dev.forceDevMode` setting enables or disables Toolkit "dev mode". Witho
368368
```
369369
tail -F ~/awstoolkit.log
370370
```
371-
- Use the `AWS (Developer): Watch Logs` command to watch and filter Toolkit logs (including
372-
telemetry) in VSCode.
373-
- Only available if you enabled "dev mode" (`aws.dev.forceDevMode` setting, see above).
374-
- Enter text in the Debug Console filter box to show only log messages with that text. <br/>
375-
<img src="./docs/images/debug-console-filter.png" alt="VSCode Debug Console" width="320"/>
371+
- Use the Output panel to watch and filter Toolkit logs (including telemetry) in VSCode.
372+
- Enter text in the Output panel filter box to show only log messages with that text.
376373
377374
#### Enabling Debug Logs
378375
379376
How to enable more detailed debug logs in the extensions.
380377
If you need to report an issue attach these to give the most detailed information.
381378
382-
1. Open the Command Palette (`cmd/ctrl` + `shift` + `p`), then search for "View Logs". Choose the correct option for the extension you want, eg: `AWS: View Logs` or `Amazon Q: View Logs`
383-
![](./docs/images/logsView.png)
379+
1. Open the Command Palette (`cmd/ctrl` + `shift` + `p`), then search for "View Logs". Choose either `AWS: View Logs` or `Amazon Q: View Logs`.
380+
- ![](./docs/images/logsView.png)
384381
2. Click the gear icon on the bottom right and select `Debug`
385-
![](./docs/images/logsSetDebug.png)
382+
- ![](./docs/images/logsSetDebug.png)
386383
3. Click the gear icon again and select `Set As Default`. This will ensure we stay in `Debug` until explicitly changed
387-
![](./docs/images/logsSetDefault.png)
384+
- ![](./docs/images/logsSetDefault.png)
388385
4. Open the Command Palette again and select `Reload Window`.
389386
5. Now you should see additional `[debug]` prefixed logs in the output.
390-
![](./docs/images/logsDebugLog.png)
387+
- ![](./docs/images/logsDebugLog.png)
391388
392389
### Telemetry
393390
394391
- See [docs/telemetry.md](./docs/telemetry.md) for guidelines on developing telemetry in this project.
395-
- To watch Toolkit telemetry events, use the `AWS (Developer): Watch Logs` command (see [Logging](#logging) above) and enter "telemetry" in the Debug Console filter box.
392+
- To watch Toolkit telemetry events, use the `Amazon Q: View Logs` command (see [Logging](#logging) above) and enter "telemetry" in the filter box.
396393
397394
### Service Endpoints
398395
-22.9 KB
Binary file not shown.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "`Send to prompt` and other context menu options not sent if chat was closed"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q /dev: support `.hbs`, `.gjs`, `.gts`, `.astro`, `.mdx`, `.svelte`, `.erb`, `.rake` files"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "/transform: automatically download results when ready"
4+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as vscode from 'vscode'
7+
import assert from 'assert'
8+
import {
9+
assertTelemetry,
10+
closeAllEditors,
11+
getTestWindow,
12+
registerAuthHook,
13+
resetCodeWhispererGlobalVariables,
14+
TestFolder,
15+
toTextEditor,
16+
using,
17+
} from 'aws-core-vscode/test'
18+
import { RecommendationHandler, RecommendationService } from 'aws-core-vscode/codewhisperer'
19+
import { Commands, globals, sleep, waitUntil } from 'aws-core-vscode/shared'
20+
import { loginToIdC } from '../amazonq/utils/setup'
21+
22+
describe('Amazon Q Inline', async function () {
23+
let tempFolder: string
24+
const waitOptions = {
25+
interval: 500,
26+
timeout: 10000,
27+
retryOnFail: false,
28+
}
29+
30+
before(async function () {
31+
await using(registerAuthHook('amazonq-test-account'), async () => {
32+
await loginToIdC()
33+
})
34+
})
35+
36+
beforeEach(async function () {
37+
registerAuthHook('amazonq-test-account')
38+
const folder = await TestFolder.create()
39+
tempFolder = folder.path
40+
await closeAllEditors()
41+
await resetCodeWhispererGlobalVariables(false)
42+
})
43+
44+
afterEach(async function () {
45+
await closeAllEditors()
46+
})
47+
48+
async function setupEditor({ name, contents }: { name?: string; contents?: string } = {}) {
49+
const fileName = name ?? 'test.ts'
50+
const textContents =
51+
contents ??
52+
`function fib() {
53+
54+
55+
}`
56+
await toTextEditor(textContents, fileName, tempFolder, {
57+
selection: new vscode.Range(new vscode.Position(1, 4), new vscode.Position(1, 4)),
58+
})
59+
}
60+
61+
async function waitForRecommendations() {
62+
const ok = await waitUntil(async () => RecommendationHandler.instance.isSuggestionVisible(), waitOptions)
63+
if (!ok) {
64+
assert.fail('Suggestions failed to become visible')
65+
}
66+
}
67+
68+
async function waitForTelemetry() {
69+
const ok = await waitUntil(
70+
async () =>
71+
globals.telemetry.logger.query({
72+
metricName: 'codewhisperer_userTriggerDecision',
73+
}).length > 0,
74+
waitOptions
75+
)
76+
if (!ok) {
77+
assert.fail('Telemetry failed to be emitted')
78+
}
79+
}
80+
81+
for (const [name, invokeCompletion] of [
82+
['automatic', async () => await vscode.commands.executeCommand('type', { text: '\n' })],
83+
['manual', async () => Commands.tryExecute('aws.amazonq.invokeInlineCompletion')],
84+
] as const) {
85+
describe(`${name} invoke`, async function () {
86+
let originalEditorContents: string | undefined
87+
88+
describe('supported filetypes', () => {
89+
beforeEach(async () => {
90+
await setupEditor()
91+
92+
/**
93+
* Allow some time between when the editor is opened and when we start typing.
94+
* If we don't do this then the time between the initial editor selection
95+
* and invoking the "type" command is too low, causing completion to never
96+
* activate. AFAICT there isn't anything we can use waitUntil on here.
97+
*
98+
* note: this number is entirely arbitrary
99+
**/
100+
await sleep(1000)
101+
102+
await invokeCompletion()
103+
originalEditorContents = vscode.window.activeTextEditor?.document.getText()
104+
105+
// wait until the ghost text appears
106+
await waitForRecommendations()
107+
})
108+
109+
it(`${name} invoke accept`, async function () {
110+
/**
111+
* keep accepting the suggestion until the text contents change
112+
* this is required because we have no access to the inlineSuggest panel
113+
**/
114+
const suggestionAccepted = await waitUntil(async () => {
115+
// Accept the suggestion
116+
await vscode.commands.executeCommand('editor.action.inlineSuggest.commit')
117+
return vscode.window.activeTextEditor?.document.getText() !== originalEditorContents
118+
}, waitOptions)
119+
120+
assert.ok(suggestionAccepted, 'Editor contents should have changed')
121+
122+
await waitForTelemetry()
123+
assertTelemetry('codewhisperer_userTriggerDecision', {
124+
codewhispererSuggestionState: 'Accept',
125+
})
126+
})
127+
128+
it(`${name} invoke reject`, async function () {
129+
// Reject the suggestion
130+
await vscode.commands.executeCommand('aws.amazonq.rejectCodeSuggestion')
131+
132+
// Contents haven't changed
133+
assert.deepStrictEqual(vscode.window.activeTextEditor?.document.getText(), originalEditorContents)
134+
135+
await waitForTelemetry()
136+
assertTelemetry('codewhisperer_userTriggerDecision', {
137+
codewhispererSuggestionState: 'Reject',
138+
})
139+
})
140+
141+
it(`${name} invoke discard`, async function () {
142+
// Discard the suggestion by moving it back to the original position
143+
const position = new vscode.Position(1, 4)
144+
const editor = vscode.window.activeTextEditor
145+
if (!editor) {
146+
assert.fail('Could not find text editor')
147+
}
148+
editor.selection = new vscode.Selection(position, position)
149+
150+
// Contents are the same
151+
assert.deepStrictEqual(vscode.window.activeTextEditor?.document.getText(), originalEditorContents)
152+
})
153+
})
154+
155+
it(`${name} invoke on unsupported filetype`, async function () {
156+
await setupEditor({
157+
name: 'test.zig',
158+
contents: `fn doSomething() void {
159+
160+
}`,
161+
})
162+
163+
/**
164+
* Add delay between editor loading and invoking completion
165+
* @see beforeEach in supported filetypes for more information
166+
*/
167+
await sleep(1000)
168+
await invokeCompletion()
169+
170+
if (name === 'automatic') {
171+
// It should never get triggered since its not a supported file type
172+
assert.deepStrictEqual(RecommendationService.instance.isRunning, false)
173+
} else {
174+
await getTestWindow().waitForMessage('currently not supported by Amazon Q inline suggestions')
175+
}
176+
})
177+
})
178+
}
179+
})

packages/core/src/amazonq/apps/initContext.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44
*/
55

66
import { EventEmitter } from 'vscode'
7-
import { MessagePublisher } from '../messages/messagePublisher'
7+
import { MessagePublisher, UiMessagePublisher } from '../messages/messagePublisher'
88
import { MessageListener } from '../messages/messageListener'
99
import { TabType } from '../webview/ui/storages/tabsStorage'
1010

1111
export interface AmazonQAppInitContext {
1212
registerWebViewToAppMessagePublisher(eventEmitter: MessagePublisher<any>, tabType: TabType): void
13-
getAppsToWebViewMessagePublisher(): MessagePublisher<any>
13+
getAppsToWebViewMessagePublisher(): UiMessagePublisher<any>
1414
onDidChangeAmazonQVisibility: EventEmitter<boolean>
1515
}
1616

1717
export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext {
1818
private readonly appsToWebViewEventEmitter = new EventEmitter<any>()
1919
private readonly appsToWebViewMessageListener = new MessageListener<any>(this.appsToWebViewEventEmitter)
20-
private readonly appsToWebViewMessagePublisher = new MessagePublisher<any>(this.appsToWebViewEventEmitter)
20+
private readonly appsToWebViewMessagePublisher = new UiMessagePublisher<any>(this.appsToWebViewEventEmitter)
2121
private readonly webViewToAppsMessagePublishers: Map<TabType, MessagePublisher<any>> = new Map()
2222
public readonly onDidChangeAmazonQVisibility = new EventEmitter<boolean>()
2323

@@ -41,7 +41,7 @@ export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext {
4141
return this.appsToWebViewMessageListener
4242
}
4343

44-
getAppsToWebViewMessagePublisher(): MessagePublisher<any> {
44+
getAppsToWebViewMessagePublisher(): UiMessagePublisher<any> {
4545
return this.appsToWebViewMessagePublisher
4646
}
4747
}

packages/core/src/amazonq/messages/messagePublisher.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,48 @@ export class MessagePublisher<T> {
1212
this.eventEmitter.fire(event)
1313
}
1414
}
15+
16+
/**
17+
* Same as {@link MessagePublisher}, but will wait until the UI indicates it
18+
* is ready to recieve messages, before the message is published.
19+
*
20+
* This solves a problem when running a right click menu option like
21+
* "Send To Prompt" BUT chat is not opened yet, it would result in the prompt failing to
22+
* be recieved by chat.
23+
*/
24+
export class UiMessagePublisher<T> extends MessagePublisher<T> {
25+
private isUiReady: boolean = false
26+
private buffer: T[] = []
27+
28+
constructor(eventEmitter: EventEmitter<T>) {
29+
super(eventEmitter)
30+
}
31+
32+
public override publish(event: T): void {
33+
// immediately send if Chat UI is ready
34+
if (this.isUiReady) {
35+
super.publish(event)
36+
return
37+
}
38+
39+
this.buffer.push(event)
40+
}
41+
42+
/**
43+
* Indicate the Q Chat UI is ready to recieve messages.
44+
*/
45+
public setUiReady() {
46+
this.isUiReady = true
47+
this.flush()
48+
}
49+
50+
/**
51+
* Publishes all blocked messages
52+
*/
53+
private flush() {
54+
for (const msg of this.buffer) {
55+
super.publish(msg)
56+
}
57+
this.buffer = []
58+
}
59+
}

packages/core/src/amazonq/webview/messages/messageDispatcher.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { telemetry } from '../../../shared/telemetry'
1313
import { AmazonQChatMessageDuration } from '../../messages/chatMessageDuration'
1414
import { globals, openUrl } from '../../../shared'
1515
import { isClickTelemetry, isOpenAgentTelemetry } from '../ui/telemetry/actions'
16+
import { DefaultAmazonQAppInitContext } from '../../apps/initContext'
1617

1718
export function dispatchWebViewMessagesToApps(
1819
webview: Webview,
@@ -21,12 +22,12 @@ export function dispatchWebViewMessagesToApps(
2122
webview.onDidReceiveMessage((msg) => {
2223
switch (msg.command) {
2324
case 'ui-is-ready': {
25+
DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().setUiReady()
2426
/**
2527
* ui-is-ready isn't associated to any tab so just record the telemetry event and continue.
2628
* This would be equivalent of the duration between "user clicked open q" and "ui has become available"
2729
* NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview.
2830
*/
29-
3031
telemetry.webview_load.emit({
3132
webviewName: 'amazonq',
3233
duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration,

packages/core/src/codewhisperer/commands/startTransformByQ.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,12 @@ export async function postTransformationJob() {
775775
if (transformByQState.getPayloadFilePath() !== '') {
776776
fs.rmSync(transformByQState.getPayloadFilePath(), { recursive: true, force: true }) // delete ZIP if it exists
777777
}
778+
779+
// attempt download for user
780+
// TODO: refactor as explained here https://github.com/aws/aws-toolkit-vscode/pull/6519/files#r1946873107
781+
if (transformByQState.isSucceeded() || transformByQState.isPartiallySucceeded()) {
782+
await vscode.commands.executeCommand('aws.amazonq.transformationHub.reviewChanges.startReview')
783+
}
778784
}
779785

780786
export async function transformationJobErrorHandler(error: any) {

0 commit comments

Comments
 (0)