Skip to content

Commit 9806f89

Browse files
committed
feat(amazonq): skip registering run command log file
1 parent e01574f commit 9806f89

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import * as vscode from 'vscode'
7+
import * as path from 'path'
78
import { ToolkitError } from '../../shared/errors'
89
import globals from '../../shared/extensionGlobals'
910
import { getLogger } from '../../shared/logger/logger'
@@ -29,6 +30,7 @@ import { prepareRepoData, getDeletedFileInfos, registerNewFiles, PrepareRepoData
2930
import { uploadCode } from '../util/upload'
3031

3132
export const EmptyCodeGenID = 'EMPTY_CURRENT_CODE_GENERATION_ID'
33+
const RunCommandLogFileName = '.amazonq/dev/run_command.log'
3234

3335
export interface BaseMessenger {
3436
sendAnswer(params: any): void
@@ -103,6 +105,22 @@ export abstract class CodeGenBase {
103105
case CodeGenerationStatus.COMPLETE: {
104106
const { newFileContents, deletedFiles, references } =
105107
await this.config.proxyClient.exportResultArchive(this.conversationId)
108+
109+
const logFileInfo = newFileContents.find(
110+
(file: { zipFilePath: string; fileContent: string }) =>
111+
file.zipFilePath === RunCommandLogFileName
112+
)
113+
if (logFileInfo) {
114+
const filePath = path.join(this.config.workspaceRoots[0], RunCommandLogFileName)
115+
const fileUri = vscode.Uri.file(filePath)
116+
117+
await fs.writeFile(fileUri, new TextEncoder().encode(logFileInfo.fileContent), {
118+
create: true,
119+
overwrite: true,
120+
})
121+
newFileContents.splice(newFileContents.indexOf(logFileInfo), 1)
122+
}
123+
106124
const newFileInfo = registerNewFiles(
107125
fs,
108126
newFileContents,

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

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ 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'
12+
import * as filesModule from '../../../amazonq/util/files'
13+
import { CodeGenBase as CodeGenBaseClass } from '../../../amazonq/session/sessionState'
1314

1415
describe('sessionStateDoc', () => {
1516
const context = createTestContext()
@@ -26,4 +27,133 @@ describe('sessionStateDoc', () => {
2627
})
2728
})
2829
})
30+
31+
describe('CodeGenBase generateCode log file handling', () => {
32+
const RunCommandLogFileName = '.amazonq/dev/run_command.log'
33+
const registerNewFilesStub = sinon.stub()
34+
registerNewFilesStub.callsFake((fs: any, newFileContents: any[]) => {
35+
return newFileContents
36+
})
37+
const getDeletedFileInfosStub = sinon.stub()
38+
getDeletedFileInfosStub.callsFake((fs: any, deletedFiles: any[]) => {
39+
return []
40+
})
41+
42+
class TestCodeGen extends CodeGenBaseClass {
43+
public generatedFiles: any[] = []
44+
constructor(config: any, tabID: string) {
45+
super(config, tabID)
46+
}
47+
protected handleProgress(messenger: any, action: any, detail?: string): void {
48+
// no-op
49+
}
50+
protected getScheme(): string {
51+
return 'file'
52+
}
53+
protected getTimeoutErrorCode(): string {
54+
return 'test_timeout'
55+
}
56+
protected handleGenerationComplete(messenger: any, newFileInfo: any[], action: any): void {
57+
this.generatedFiles = newFileInfo
58+
}
59+
protected handleError(messenger: any, codegenResult: any): Error {
60+
throw new Error('handleError called')
61+
}
62+
}
63+
64+
let testConfig: any
65+
let fakeProxyClient: any
66+
let fsMock: any
67+
let telemetryMock: any
68+
let messengerMock: any
69+
let testAction: any
70+
71+
beforeEach(() => {
72+
fakeProxyClient = {
73+
getCodeGeneration: sinon.stub().resolves({
74+
codeGenerationStatus: { status: 'Complete' },
75+
codeGenerationRemainingIterationCount: 0,
76+
codeGenerationTotalIterationCount: 1,
77+
}),
78+
exportResultArchive: sinon.stub(),
79+
}
80+
81+
testConfig = {
82+
conversationId: 'conv1',
83+
uploadId: 'upload1',
84+
workspaceRoots: ['/workspace'],
85+
proxyClient: fakeProxyClient,
86+
}
87+
88+
fsMock = {
89+
stat: sinon.stub(),
90+
readFile: sinon.stub(),
91+
writeFile: sinon.stub(),
92+
}
93+
94+
telemetryMock = {
95+
setCodeGenerationResult: sinon.spy(),
96+
setNumberOfFilesGenerated: sinon.spy(),
97+
setAmazonqNumberOfReferences: sinon.spy(),
98+
setGenerateCodeIteration: sinon.spy(),
99+
setGenerateCodeLastInvocationTime: sinon.spy(),
100+
recordUserCodeGenerationTelemetry: sinon.spy(),
101+
}
102+
103+
messengerMock = {
104+
sendAnswer: sinon.spy(),
105+
}
106+
107+
testAction = {
108+
telemetry: telemetryMock,
109+
fs: fsMock,
110+
messenger: messengerMock,
111+
uploadHistory: {},
112+
tokenSource: { token: { isCancellationRequested: false, onCancellationRequested: () => {} } },
113+
}
114+
})
115+
116+
afterEach(() => {
117+
sinon.restore()
118+
})
119+
120+
it('writes to the log file, present or not', async () => {
121+
const logFileInfo = {
122+
zipFilePath: RunCommandLogFileName,
123+
fileContent: 'newLog',
124+
}
125+
const otherFile = { zipFilePath: 'other.ts', fileContent: 'other' }
126+
127+
fakeProxyClient.exportResultArchive.resolves({
128+
newFileContents: [logFileInfo, otherFile],
129+
deletedFiles: [],
130+
references: [],
131+
})
132+
133+
fsMock.writeFile.resolves()
134+
135+
sinon.stub(filesModule, 'registerNewFiles').callsFake(registerNewFilesStub)
136+
sinon.stub(filesModule, 'getDeletedFileInfos').callsFake(getDeletedFileInfosStub)
137+
138+
const testCodeGen = new TestCodeGen(testConfig, 'tab1')
139+
140+
await testCodeGen.generateCode({
141+
messenger: messengerMock,
142+
fs: fsMock,
143+
codeGenerationId: 'codegen2',
144+
telemetry: telemetryMock,
145+
workspaceFolders: {},
146+
action: testAction,
147+
})
148+
149+
const expectedFilePath = `${testConfig.workspaceRoots[0]}/${RunCommandLogFileName}`
150+
const fileUri = vscode.Uri.file(expectedFilePath)
151+
sinon.assert.calledWith(fsMock.writeFile, fileUri, new TextEncoder().encode('newLog'), {
152+
create: true,
153+
overwrite: true,
154+
})
155+
156+
assert.deepStrictEqual(testCodeGen.generatedFiles, [otherFile])
157+
})
158+
})
29159
})

0 commit comments

Comments
 (0)