Skip to content

Commit 02a418c

Browse files
committed
updated tests to account for no diff.json and performed e2e transformation assuming current download artifact workflow
1 parent e853153 commit 02a418c

File tree

6 files changed

+104
-66
lines changed

6 files changed

+104
-66
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"name": "Added file",
4+
"fileName": "resources/files/addedFile.diff",
5+
"isSuccessful": true
6+
}
7+
]

packages/amazonq/test/unit/amazonqGumby/transformationResultsHandler.test.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import { getTestResourceFilePath } from './amazonQGumbyUtil'
1212
import { fs } from 'aws-core-vscode/shared'
1313

1414
describe('DiffModel', function () {
15-
let parsedTestDescription: PatchInfo
15+
let parsedTestDescriptions: PatchInfo[]
1616
beforeEach(() => {
17-
parsedTestDescription = JSON.parse(
18-
'{"name": "Added file", "fileName": "resources/files/addedFile.diff", "isSuccessful": true}'
17+
const fs = require('fs')
18+
parsedTestDescriptions = JSON.parse(
19+
fs.readFileSync(getTestResourceFilePath('resources/files/diff.json'), 'utf-8')
1920
)
2021
})
2122

@@ -36,16 +37,15 @@ describe('DiffModel', function () {
3637

3738
return true
3839
})
39-
4040
testDiffModel.parseDiff(
4141
getTestResourceFilePath('resources/files/addedFile.diff'),
4242
workspacePath,
43-
parsedTestDescription
43+
parsedTestDescriptions[0]
4444
)
4545

4646
assert.strictEqual(testDiffModel.patchFileNodes.length, 1)
4747
assert.strictEqual(testDiffModel.patchFileNodes[0].children.length, 1)
48-
assert.strictEqual(testDiffModel.patchFileNodes[0].patchFilePath, parsedTestDescription.name)
48+
assert.strictEqual(testDiffModel.patchFileNodes[0].patchFilePath, parsedTestDescriptions[0].name)
4949
const change = testDiffModel.patchFileNodes[0].children[0]
5050

5151
assert.strictEqual(change instanceof AddedChangeNode, true)
@@ -66,12 +66,39 @@ describe('DiffModel', function () {
6666
testDiffModel.parseDiff(
6767
getTestResourceFilePath('resources/files/modifiedFile.diff'),
6868
workspacePath,
69-
parsedTestDescription
69+
parsedTestDescriptions[0]
7070
)
7171

7272
assert.strictEqual(testDiffModel.patchFileNodes.length, 1)
7373
assert.strictEqual(testDiffModel.patchFileNodes[0].children.length, 1)
74-
assert.strictEqual(testDiffModel.patchFileNodes[0].patchFilePath, parsedTestDescription.name)
74+
assert.strictEqual(testDiffModel.patchFileNodes[0].patchFilePath, parsedTestDescriptions[0].name)
75+
const change = testDiffModel.patchFileNodes[0].children[0]
76+
77+
assert.strictEqual(change instanceof ModifiedChangeNode, true)
78+
79+
await fs.delete(path.join(workspacePath, 'README.md'), { recursive: true })
80+
})
81+
82+
it('WHEN parsing a diff patch where diff.json is not present and a file was modified THEN returns an array representing the modified file', async function () {
83+
const testDiffModel = new DiffModel()
84+
85+
const workspacePath = os.tmpdir()
86+
87+
sinon.replace(fs, 'exists', async (path) => true)
88+
89+
await fs.writeFile(
90+
path.join(workspacePath, 'README.md'),
91+
'This guide walks you through using Gradle to build a simple Java project.'
92+
)
93+
94+
testDiffModel.parseDiff(getTestResourceFilePath('resources/files/modifiedFile.diff'), workspacePath, undefined)
95+
96+
assert.strictEqual(testDiffModel.patchFileNodes.length, 1)
97+
assert.strictEqual(testDiffModel.patchFileNodes[0].children.length, 1)
98+
assert.strictEqual(
99+
testDiffModel.patchFileNodes[0].patchFilePath,
100+
getTestResourceFilePath('resources/files/modifiedFile.diff')
101+
)
75102
const change = testDiffModel.patchFileNodes[0].children[0]
76103

77104
assert.strictEqual(change instanceof ModifiedChangeNode, true)

packages/core/src/amazonqGumby/chat/controller/controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { featureName } from '../../models/constants'
1717
import { AuthUtil } from '../../../codewhisperer/util/authUtil'
1818
import {
1919
cleanupTransformationJob,
20-
// compileProject,
20+
compileProject,
2121
finishHumanInTheLoop,
2222
getValidCandidateProjects,
2323
openBuildLogFile,
@@ -405,7 +405,7 @@ export class GumbyController {
405405
try {
406406
this.sessionStorage.getSession().conversationState = ConversationState.COMPILING
407407
this.messenger.sendCompilationInProgress(message.tabID)
408-
// await compileProject()
408+
await compileProject()
409409
} catch (err: any) {
410410
this.messenger.sendUnrecoverableErrorResponse('could-not-compile-project', message.tabID)
411411
// reset state to allow "Start a new transformation" button to work

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ import { dependencyNoAvailableVersions } from '../../amazonqGumby/models/constan
7373
import { HumanInTheLoopManager } from '../service/transformByQ/humanInTheLoopManager'
7474
import { setContext } from '../../shared/vscode/setContext'
7575
import { makeTemporaryToolkitFolder } from '../../shared'
76-
// import globals from '../../shared/extensionGlobals'
76+
import globals from '../../shared/extensionGlobals'
7777

7878
function getFeedbackCommentData() {
7979
const jobId = transformByQState.getJobId()
@@ -165,24 +165,24 @@ export function startInterval() {
165165

166166
export async function startTransformByQ() {
167167
// Set the default state variables for our store and the UI
168-
// const transformStartTime = globals.clock.Date.now()
168+
const transformStartTime = globals.clock.Date.now()
169169
await setTransformationToRunningState()
170170

171171
try {
172172
// Set webview UI to poll for progress
173173
startInterval()
174174

175175
// step 1: CreateUploadUrl and upload code
176-
// const uploadId = await preTransformationUploadCode()
176+
const uploadId = await preTransformationUploadCode()
177177

178178
// step 2: StartJob and store the returned jobId in TransformByQState
179-
// const jobId = await startTransformationJob(uploadId, transformStartTime)
179+
const jobId = await startTransformationJob(uploadId, transformStartTime)
180180

181181
// step 3 (intermediate step): show transformation-plan.md file
182-
// await pollTransformationStatusUntilPlanReady(jobId)
182+
await pollTransformationStatusUntilPlanReady(jobId)
183183

184184
// step 4: poll until artifacts are ready to download
185-
await humanInTheLoopRetryLogic('jobId')
185+
await humanInTheLoopRetryLogic(jobId)
186186
} catch (error: any) {
187187
await transformationJobErrorHandler(error)
188188
} finally {
@@ -201,8 +201,7 @@ export async function startTransformByQ() {
201201
export async function humanInTheLoopRetryLogic(jobId: string) {
202202
let status = ''
203203
try {
204-
// status = await pollTransformationStatusUntilComplete(jobId)
205-
status = 'COMPLETED'
204+
status = await pollTransformationStatusUntilComplete(jobId)
206205
if (status === 'PAUSED') {
207206
const hilStatusFailure = await initiateHumanInTheLoopPrompt(jobId)
208207
if (hilStatusFailure) {

packages/core/src/codewhisperer/service/transformByQ/transformationResultsViewProvider.ts

Lines changed: 52 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
// import AdmZip from 'adm-zip'
6+
import AdmZip from 'adm-zip'
77
import os from 'os'
88
import fs from 'fs' // eslint-disable-line no-restricted-imports
99
import { parsePatch, applyPatches, ParsedDiff } from 'diff'
1010
import path from 'path'
1111
import vscode from 'vscode'
12-
// import { ExportIntent } from '@amzn/codewhisperer-streaming'
12+
import { ExportIntent } from '@amzn/codewhisperer-streaming'
1313
import { TransformByQReviewStatus, transformByQState, PatchInfo } from '../../models/model'
14-
import { ExportResultArchiveStructure } from '../../../shared/utilities/download'
14+
import { ExportResultArchiveStructure, downloadExportResultArchive } from '../../../shared/utilities/download'
1515
import { getLogger } from '../../../shared/logger'
1616
import { telemetry } from '../../../shared/telemetry/telemetry'
1717
import { CodeTransformTelemetryState } from '../../../amazonqGumby/telemetry/codeTransformTelemetryState'
1818
import { MetadataResult } from '../../../shared/telemetry/telemetryClient'
1919
import * as CodeWhispererConstants from '../../models/constants'
20-
// import { createCodeWhispererChatStreamingClient } from '../../../shared/clients/codewhispererChatClient'
20+
import { createCodeWhispererChatStreamingClient } from '../../../shared/clients/codewhispererChatClient'
2121
import { ChatSessionManager } from '../../../amazonqGumby/chat/storages/chatSession'
2222
import { setContext } from '../../../shared/vscode/setContext'
2323

@@ -154,7 +154,11 @@ export class DiffModel {
154154
* @param pathToWorkspace Path to the project that was transformed
155155
* @returns List of nodes containing the paths of files that were modified, added, or removed
156156
*/
157-
public parseDiff(pathToDiff: string, pathToWorkspace: string, diffDescription: PatchInfo): PatchFileNode {
157+
public parseDiff(
158+
pathToDiff: string,
159+
pathToWorkspace: string,
160+
diffDescription: PatchInfo | undefined
161+
): PatchFileNode {
158162
this.patchFileNodes = []
159163
const diffContents = fs.readFileSync(pathToDiff, 'utf8')
160164
const changedFiles = parsePatch(diffContents)
@@ -190,7 +194,7 @@ export class DiffModel {
190194
}
191195
},
192196
})
193-
const patchFileNode = new PatchFileNode(diffDescription.name)
197+
const patchFileNode = new PatchFileNode(diffDescription ? diffDescription.name : pathToDiff)
194198
patchFileNode.children = changedFiles.flatMap((file) => {
195199
/* ex. file.oldFileName = 'a/src/java/com/project/component/MyFile.java'
196200
* ex. file.newFileName = 'b/src/java/com/project/component/MyFile.java'
@@ -304,26 +308,9 @@ export class ProposedTransformationExplorer {
304308
treeDataProvider: transformDataProvider,
305309
})
306310

307-
const pathContainingArchive = '/private/var/folders/mn/l6c4t6sd1jn7g4p4nb6wqhh80000gq/T/ExportResultArchive'
308-
311+
// const pathContainingArchive = '/private/var/folders/mn/l6c4t6sd1jn7g4p4nb6wqhh80000gq/T/ExportResultArchive'
309312
const patchFiles: string[] = []
310-
fs.readdir(path.join(pathContainingArchive, 'patch'), (err, files) => {
311-
if (err) {
312-
getLogger().error(err)
313-
} else {
314-
files.forEach((file) => {
315-
const filePath = path.join(pathContainingArchive, 'patch', file)
316-
if (file.endsWith('.patch')) {
317-
patchFiles.push(filePath)
318-
}
319-
})
320-
}
321-
})
322-
323-
const pathContainingPatchFileDescriptions = path.join(pathContainingArchive, 'patch', 'diff.json')
324-
325-
const jsonData = fs.readFileSync(pathContainingPatchFileDescriptions, 'utf-8')
326-
const patchFilesDescriptions: PatchInfo[] = JSON.parse(jsonData)
313+
let patchFilesDescriptions: PatchInfo[] | undefined = undefined
327314

328315
const reset = async () => {
329316
await setContext('gumby.transformationProposalReviewInProgress', false)
@@ -373,15 +360,15 @@ export class ProposedTransformationExplorer {
373360
vscode.commands.registerCommand('aws.amazonq.transformationHub.reviewChanges.startReview', async () => {
374361
await setContext('gumby.reviewState', TransformByQReviewStatus.PreparingReview)
375362

376-
// const pathToArchive = path.join(
377-
// ProposedTransformationExplorer.TmpDir,
378-
// transformByQState.getJobId(),
379-
// 'ExportResultsArchive.zip'
380-
// )
381-
const exportResultsArchiveSize = 0
363+
const pathToArchive = path.join(
364+
ProposedTransformationExplorer.TmpDir,
365+
transformByQState.getJobId(),
366+
'ExportResultsArchive.zip'
367+
)
368+
let exportResultsArchiveSize = 0
382369
let downloadErrorMessage = undefined
383370

384-
// const cwStreamingClient = await createCodeWhispererChatStreamingClient()
371+
const cwStreamingClient = await createCodeWhispererChatStreamingClient()
385372
try {
386373
await telemetry.codeTransform_downloadArtifact.run(async () => {
387374
telemetry.record({
@@ -390,17 +377,17 @@ export class ProposedTransformationExplorer {
390377
codeTransformJobId: transformByQState.getJobId(),
391378
})
392379

393-
// await downloadExportResultArchive(
394-
// cwStreamingClient,
395-
// {
396-
// exportId: transformByQState.getJobId(),
397-
// exportIntent: ExportIntent.TRANSFORMATION,
398-
// },
399-
// pathToArchive
400-
// )
380+
await downloadExportResultArchive(
381+
cwStreamingClient,
382+
{
383+
exportId: transformByQState.getJobId(),
384+
exportIntent: ExportIntent.TRANSFORMATION,
385+
},
386+
pathToArchive
387+
)
401388

402389
// Update downloaded artifact size
403-
// exportResultsArchiveSize = (await fs.promises.stat(pathToArchive)).size
390+
exportResultsArchiveSize = (await fs.promises.stat(pathToArchive)).size
404391

405392
telemetry.record({ codeTransformTotalByteSize: exportResultsArchiveSize })
406393
})
@@ -421,18 +408,34 @@ export class ProposedTransformationExplorer {
421408
getLogger().error(`CodeTransformation: ExportResultArchive error = ${downloadErrorMessage}`)
422409
throw new Error('Error downloading diff')
423410
} finally {
424-
// cwStreamingClient.destroy()
411+
cwStreamingClient.destroy()
425412
}
426413

427414
let deserializeErrorMessage = undefined
415+
let pathContainingArchive = ''
428416
try {
429417
// Download and deserialize the zip
430-
// pathContainingArchive = path.dirname(pathToArchive)
431-
// const zip = new AdmZip(pathToArchive)
432-
// zip.extractAllTo(pathContainingArchive)
418+
pathContainingArchive = path.dirname(pathToArchive)
419+
const zip = new AdmZip(pathToArchive)
420+
zip.extractAllTo(pathContainingArchive)
421+
422+
const files = fs.readdirSync(path.join(pathContainingArchive, ExportResultArchiveStructure.PathToPatch))
423+
files.forEach((file) => {
424+
const filePath = path.join(pathContainingArchive, ExportResultArchiveStructure.PathToPatch, file)
425+
if (file.endsWith('.patch')) {
426+
patchFiles.push(filePath)
427+
} else if (file.endsWith('.json')) {
428+
const jsonData = fs.readFileSync(filePath, 'utf-8')
429+
patchFilesDescriptions = JSON.parse(jsonData)
430+
}
431+
})
433432

434433
//Because multiple patches are returned once the ZIP is downloaded, we want to show the first one to start
435-
diffModel.parseDiff(patchFiles[0], transformByQState.getProjectPath(), patchFilesDescriptions[0])
434+
diffModel.parseDiff(
435+
patchFiles[0],
436+
transformByQState.getProjectPath(),
437+
patchFilesDescriptions ? patchFilesDescriptions[0] : undefined
438+
)
436439

437440
await setContext('gumby.reviewState', TransformByQReviewStatus.InReview)
438441
transformDataProvider.refresh()
@@ -478,7 +481,9 @@ export class ProposedTransformationExplorer {
478481
diffModel.currentPatchIndex++
479482
if (diffModel.currentPatchIndex < patchFiles.length) {
480483
const nextPatchFile = patchFiles[diffModel.currentPatchIndex]
481-
const nextPatchFileDescription = patchFilesDescriptions[diffModel.currentPatchIndex]
484+
const nextPatchFileDescription = patchFilesDescriptions
485+
? patchFilesDescriptions[diffModel.currentPatchIndex]
486+
: undefined
482487
diffModel.parseDiff(nextPatchFile, transformByQState.getProjectPath(), nextPatchFileDescription)
483488
transformDataProvider.refresh()
484489
} else {

packages/core/src/shared/utilities/download.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import fs from '../fs/fs'
1313
*/
1414
export class ExportResultArchiveStructure {
1515
static readonly PathToSummary = path.join('summary', 'summary.md')
16-
static readonly PathToDiffPatch = path.join('patch', 'diff.patch')
16+
static readonly PathToPatch = 'patch'
1717
static readonly PathToManifest = 'manifest.json'
1818
}
1919

0 commit comments

Comments
 (0)