Skip to content

Commit b15588f

Browse files
committed
feat(amazonq): skip registering run command log file
1 parent c3ea31d commit b15588f

File tree

5 files changed

+193
-2
lines changed

5 files changed

+193
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "The logs emitted by the Agent during user command execution will be accepted and written to .amazonq/dev/run_command.log file in the user's local repository."
4+
}

packages/core/src/amazonq/session/sessionState.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { prepareRepoData, getDeletedFileInfos, registerNewFiles, PrepareRepoData
2929
import { uploadCode } from '../util/upload'
3030

3131
export const EmptyCodeGenID = 'EMPTY_CURRENT_CODE_GENERATION_ID'
32+
export const RunCommandLogFileName = '.amazonq/dev/run_command.log'
3233

3334
export interface BaseMessenger {
3435
sendAnswer(params: any): void
@@ -103,6 +104,16 @@ export abstract class CodeGenBase {
103104
case CodeGenerationStatus.COMPLETE: {
104105
const { newFileContents, deletedFiles, references } =
105106
await this.config.proxyClient.exportResultArchive(this.conversationId)
107+
108+
const logFileInfo = newFileContents.find(
109+
(file: { zipFilePath: string; fileContent: string }) =>
110+
file.zipFilePath === RunCommandLogFileName
111+
)
112+
if (logFileInfo) {
113+
getLogger().info(`Run Command logs: \n ${logFileInfo.fileContent}`)
114+
newFileContents.splice(newFileContents.indexOf(logFileInfo), 1)
115+
}
116+
106117
const newFileInfo = registerNewFiles(
107118
fs,
108119
newFileContents,

packages/core/src/shared/virtualFilesystem.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ export class VirtualFileSystem implements vscode.FileSystemProvider {
4646
if (this.fileProviders[key] !== undefined) {
4747
throw new Error('Cannot re-register a provider for the same URI')
4848
}
49-
5049
this.fileProviders[key] = provider
5150
const onDidChange = provider.onDidChange(() => {
5251
this._onDidChangeFile.fire([{ uri, type: vscode.FileChangeType.Changed }])
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
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 sinon from 'sinon'
8+
import { CodeGenBase } from '../../../amazonq/session/sessionState'
9+
import { RunCommandLogFileName } from '../../../amazonq/session/sessionState'
10+
import assert from 'assert'
11+
import * as workspaceUtils from '../../../shared/utilities/workspaceUtils'
12+
13+
describe('CodeGenBase generateCode log file handling', () => {
14+
class TestCodeGen extends CodeGenBase {
15+
public generatedFiles: any[] = []
16+
constructor(config: any, tabID: string) {
17+
super(config, tabID)
18+
}
19+
protected handleProgress(_messenger: any): void {
20+
// No-op for test.
21+
}
22+
protected getScheme(): string {
23+
return 'file'
24+
}
25+
protected getTimeoutErrorCode(): string {
26+
return 'test_timeout'
27+
}
28+
protected handleGenerationComplete(_messenger: any, newFileInfo: any[]): void {
29+
this.generatedFiles = newFileInfo
30+
}
31+
protected handleError(_messenger: any, _codegenResult: any): Error {
32+
throw new Error('handleError called')
33+
}
34+
}
35+
36+
let fakeProxyClient: any
37+
let testConfig: any
38+
let fsMock: any
39+
let messengerMock: any
40+
let telemetryMock: any
41+
let loggerMock: any
42+
let testAction: any
43+
44+
beforeEach(async () => {
45+
// const workspaceFolder = await createTestWorkspace(1, { workspaceName: 'test-workspace-folder' })
46+
const ret = {
47+
testworkspacefolder: {
48+
uri: vscode.Uri.file('/path/to/testworkspacefolder'),
49+
name: 'testworkspacefolder',
50+
index: 0,
51+
},
52+
}
53+
// Stub getWorkspaceFoldersByPrefixes to return the real workspace folder.
54+
sinon.stub(workspaceUtils, 'getWorkspaceFoldersByPrefixes').returns(ret)
55+
56+
fakeProxyClient = {
57+
getCodeGeneration: sinon.stub().resolves({
58+
codeGenerationStatus: { status: 'Complete' },
59+
codeGenerationRemainingIterationCount: 0,
60+
codeGenerationTotalIterationCount: 1,
61+
}),
62+
exportResultArchive: sinon.stub(),
63+
}
64+
65+
testConfig = {
66+
conversationId: 'conv_test',
67+
uploadId: 'upload_test',
68+
workspaceRoots: ['/path/to/testworkspacefolder'],
69+
proxyClient: fakeProxyClient,
70+
}
71+
72+
fsMock = {
73+
writeFile: sinon.stub().resolves(),
74+
registerProvider: sinon.stub().resolves(),
75+
}
76+
77+
messengerMock = { sendAnswer: sinon.spy() }
78+
79+
telemetryMock = {
80+
setCodeGenerationResult: sinon.spy(),
81+
setNumberOfFilesGenerated: sinon.spy(),
82+
setAmazonqNumberOfReferences: sinon.spy(),
83+
setGenerateCodeIteration: sinon.spy(),
84+
setGenerateCodeLastInvocationTime: sinon.spy(),
85+
recordUserCodeGenerationTelemetry: sinon.spy(),
86+
}
87+
88+
loggerMock = {
89+
info: sinon.spy(),
90+
}
91+
92+
testAction = {
93+
fs: fsMock,
94+
messenger: messengerMock,
95+
logger: loggerMock,
96+
tokenSource: {
97+
token: {
98+
isCancellationRequested: false,
99+
onCancellationRequested: () => {},
100+
},
101+
},
102+
}
103+
})
104+
105+
afterEach(() => {
106+
sinon.restore()
107+
})
108+
109+
it('adds the log content to logger if present and excludes it from new files', async () => {
110+
const logFileInfo = {
111+
zipFilePath: RunCommandLogFileName,
112+
fileContent: 'newLog',
113+
}
114+
const otherFile = { zipFilePath: 'other.ts', fileContent: 'other content' }
115+
fakeProxyClient.exportResultArchive.resolves({
116+
newFileContents: [logFileInfo, otherFile],
117+
deletedFiles: [],
118+
references: [],
119+
})
120+
121+
const testCodeGen = new TestCodeGen(testConfig, 'tab1')
122+
123+
const result = await testCodeGen.generateCode({
124+
messenger: messengerMock,
125+
fs: fsMock,
126+
codeGenerationId: 'codegen1',
127+
telemetry: telemetryMock,
128+
workspaceFolders: [testConfig.workspaceRoots[0]],
129+
action: testAction,
130+
})
131+
132+
// Use regex for logger message matching to allow flexibility with spacing/newlines
133+
sinon.assert.calledWith(
134+
loggerMock.info,
135+
sinon.match(new RegExp(`Run Command logs:\\s*${logFileInfo.fileContent}`))
136+
)
137+
// Expect only other file to be returned in newFiles
138+
assert.deepStrictEqual(result.newFiles, [otherFile])
139+
})
140+
141+
it('skips log file handling if log file is not present', async () => {
142+
const file1 = { zipFilePath: 'file1.ts', fileContent: 'content1' }
143+
fakeProxyClient.exportResultArchive.resolves({
144+
newFileContents: [file1],
145+
deletedFiles: [],
146+
references: [],
147+
})
148+
149+
const testCodeGen = new TestCodeGen(testConfig, 'tab1')
150+
151+
const result = await testCodeGen.generateCode({
152+
messenger: messengerMock,
153+
fs: fsMock,
154+
codeGenerationId: 'codegen2',
155+
telemetry: telemetryMock,
156+
workspaceFolders: [testConfig.workspaceRoots[0]],
157+
action: testAction,
158+
})
159+
160+
sinon.assert.notCalled(loggerMock.info)
161+
162+
// Build the expected output to include the additional properties added by generateCode
163+
const expectedNewFile = {
164+
zipFilePath: 'file1.ts',
165+
fileContent: 'content1',
166+
changeApplied: false,
167+
rejected: false,
168+
relativePath: 'file1.ts',
169+
virtualMemoryUri: vscode.Uri.file(`/upload_test/file1.ts`),
170+
workspaceFolder: {
171+
index: 0,
172+
name: 'testworkspacefolder',
173+
uri: vscode.Uri.file('/path/to/testworkspacefolder'),
174+
},
175+
}
176+
assert.deepStrictEqual(result.newFiles, [expectedNewFile])
177+
})
178+
})

packages/core/src/test/amazonqDoc/session/sessionState.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import assert from 'assert'
88
import sinon from 'sinon'
99
import { DocPrepareCodeGenState } from '../../../amazonqDoc'
1010
import { createMockSessionStateAction } from '../../amazonq/utils'
11-
1211
import { createTestContext, setupTestHooks } from '../../amazonq/session/testSetup'
1312

1413
describe('sessionStateDoc', () => {

0 commit comments

Comments
 (0)