Skip to content

Commit 8ecf057

Browse files
dhasani23David Hasani
andauthored
fix: reorder input checks, remove modals, add jobId to table (#4184)
* fix: reorder input checks, remove modals, add jobId to table * fix: fix unit test * fix: fix unit test * fix: address comments * fix: omit redundant metric emission * nit: modify error message --------- Co-authored-by: David Hasani <[email protected]>
1 parent 4dc6386 commit 8ecf057

File tree

7 files changed

+77
-85
lines changed

7 files changed

+77
-85
lines changed

src/codewhisperer/commands/startTransformByQ.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ export async function startTransformByQ() {
256256
} catch (error) {
257257
if (transformByQState.isCancelled()) {
258258
stopJob(transformByQState.getJobId())
259-
vscode.window.showErrorMessage(CodeWhispererConstants.transformByQCancelledMessage, { modal: true })
259+
vscode.window.showErrorMessage(CodeWhispererConstants.transformByQCancelledMessage)
260260
} else {
261261
transformByQState.setToFailed()
262262
let displayedErrorMessage = CodeWhispererConstants.transformByQFailedMessage
@@ -266,7 +266,7 @@ export async function startTransformByQ() {
266266
if (transformByQState.getJobFailureReason() !== '') {
267267
displayedErrorMessage += `: ${transformByQState.getJobFailureReason()}`
268268
}
269-
vscode.window.showErrorMessage(displayedErrorMessage, { modal: true })
269+
vscode.window.showErrorMessage(displayedErrorMessage)
270270
}
271271
if (sessionPlanProgress['uploadCode'] !== StepProgress.Succeeded) {
272272
sessionPlanProgress['uploadCode'] = StepProgress.Failed
@@ -295,14 +295,11 @@ export async function startTransformByQ() {
295295
)
296296
}
297297
if (transformByQState.isSucceeded()) {
298-
vscode.window.showInformationMessage(CodeWhispererConstants.transformByQCompletedMessage, { modal: true })
298+
vscode.window.showInformationMessage(CodeWhispererConstants.transformByQCompletedMessage)
299299
} else if (transformByQState.isPartiallySucceeded()) {
300-
vscode.window.showInformationMessage(CodeWhispererConstants.transformByQPartiallyCompletedMessage, {
301-
modal: true,
302-
})
300+
vscode.window.showInformationMessage(CodeWhispererConstants.transformByQPartiallyCompletedMessage)
303301
}
304302
}
305-
await sleep(2000) // needed as a buffer to allow TransformationHub to update before state is updated
306303
clearInterval(intervalId)
307304
transformByQState.setToNotStarted() // so that the "Transform by Q" button resets
308305
transformByQState.setPolledJobStatus('') // reset polled job status too

src/codewhisperer/models/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ export const dependencyDisclaimer =
323323
export const dependencyFolderName = 'transformation_dependencies_temp_'
324324

325325
export const dependencyErrorMessage =
326-
'Failed to execute Maven. It is possible that the upload does not include all dependencies.'
326+
'Failed to execute Maven. It is possible that the upload does not include all dependencies. We will still attempt to complete the transformation.'
327327

328328
export const planIntroductionMessage =
329329
'We reviewed your Java JAVA_VERSION_HERE application and generated a transformation plan. Any code changes made to your application will be done in the sandbox so as to not interfere with your working repository. Once the transformation job is done, we will share the new code which you can review before acccepting the code changes. In the meantime, you can work on your codebase and invoke Q Chat to answer questions about your codebase.'

src/codewhisperer/models/model.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,12 @@ export enum JDKVersion {
241241
JDK17 = '17',
242242
}
243243

244+
export enum BuildSystem {
245+
Maven = 'Maven',
246+
Gradle = 'Gradle',
247+
Unknown = 'Unknown',
248+
}
249+
244250
export enum DropdownStep {
245251
STEP_1 = 1,
246252
STEP_2 = 2,

src/codewhisperer/service/transformByQHandler.ts

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

6-
import { transformByQState, TransformByQStoppedError, ZipManifest } from '../models/model'
6+
import { BuildSystem, transformByQState, TransformByQStoppedError, ZipManifest } from '../models/model'
77
import * as codeWhisperer from '../client/codewhisperer'
88
import * as crypto from 'crypto'
99
import { getLogger } from '../../shared/logger'
@@ -64,7 +64,7 @@ export function throwIfCancelled() {
6464
export async function getOpenProjects() {
6565
const folders = vscode.workspace.workspaceFolders
6666
if (folders === undefined) {
67-
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage, { modal: true })
67+
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage)
6868
throw new ToolkitError('No Java projects found since no projects are open', { code: 'NoOpenProjects' })
6969
}
7070
const openProjects: vscode.QuickPickItem[] = []
@@ -84,13 +84,24 @@ export async function getOpenProjects() {
8484
*/
8585
export async function validateProjectSelection(project: vscode.QuickPickItem) {
8686
const projectPath = project.description
87+
const buildSystem = await checkBuildSystem(projectPath!)
88+
if (buildSystem !== BuildSystem.Maven) {
89+
vscode.window.showErrorMessage(CodeWhispererConstants.noPomXmlFoundMessage)
90+
telemetry.codeTransform_isDoubleClickedToTriggerInvalidProject.emit({
91+
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
92+
codeTransformPreValidationError: 'NonMavenProject',
93+
result: MetadataResult.Fail,
94+
reason: buildSystem === BuildSystem.Gradle ? buildSystem : 'NoPomFileFound',
95+
})
96+
throw new ToolkitError('No valid Maven build file found', { code: 'CouldNotFindPomXml' })
97+
}
8798
const compiledJavaFiles = await vscode.workspace.findFiles(
8899
new vscode.RelativePattern(projectPath!, '**/*.class'),
89100
'**/node_modules/**',
90101
1
91102
)
92103
if (compiledJavaFiles.length < 1) {
93-
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage, { modal: true })
104+
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage)
94105
telemetry.codeTransform_isDoubleClickedToTriggerInvalidProject.emit({
95106
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
96107
codeTransformPreValidationError: 'NoJavaProject',
@@ -105,7 +116,7 @@ export async function validateProjectSelection(project: vscode.QuickPickItem) {
105116
const spawnResult = spawnSync(baseCommand, args, { shell: false, encoding: 'utf-8' })
106117

107118
if (spawnResult.error || spawnResult.status !== 0) {
108-
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage, { modal: true })
119+
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage)
109120
telemetry.codeTransform_isDoubleClickedToTriggerInvalidProject.emit({
110121
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
111122
codeTransformPreValidationError: 'NoJavaProject',
@@ -124,7 +135,7 @@ export async function validateProjectSelection(project: vscode.QuickPickItem) {
124135
} else if (javaVersion === CodeWhispererConstants.JDK11VersionNumber) {
125136
transformByQState.setSourceJDKVersionToJDK11()
126137
} else {
127-
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage, { modal: true })
138+
vscode.window.showErrorMessage(CodeWhispererConstants.noSupportedJavaProjectsFoundMessage)
128139
telemetry.codeTransform_isDoubleClickedToTriggerInvalidProject.emit({
129140
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
130141
codeTransformPreValidationError: 'UnsupportedJavaVersion',
@@ -133,30 +144,6 @@ export async function validateProjectSelection(project: vscode.QuickPickItem) {
133144
})
134145
throw new ToolkitError('Project selected is not Java 8 or Java 11', { code: 'UnsupportedJavaVersion' })
135146
}
136-
const buildFile = await vscode.workspace.findFiles(
137-
new vscode.RelativePattern(projectPath!, 'pom.xml'), // check for pom.xml in root directory only
138-
'**/node_modules/**',
139-
1
140-
)
141-
if (buildFile.length < 1) {
142-
const buildType = await checkIfGradle(projectPath!)
143-
vscode.window.showErrorMessage(CodeWhispererConstants.noPomXmlFoundMessage, { modal: true })
144-
if (buildType === 'Gradle') {
145-
telemetry.codeTransform_isDoubleClickedToTriggerInvalidProject.emit({
146-
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
147-
codeTransformPreValidationError: 'NonMavenProject',
148-
result: MetadataResult.Fail,
149-
reason: buildType,
150-
})
151-
}
152-
telemetry.codeTransform_isDoubleClickedToTriggerInvalidProject.emit({
153-
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
154-
codeTransformPreValidationError: 'NoPom',
155-
result: MetadataResult.Fail,
156-
reason: 'CouldNotFindPomXml',
157-
})
158-
throw new ToolkitError('No valid Maven build file found', { code: 'CouldNotFindPomXml' })
159-
}
160147
}
161148

162149
export function getSha256(fileName: string) {
@@ -188,7 +175,6 @@ export async function uploadArtifactToS3(fileName: string, resp: CreateUploadUrl
188175
const sha256 = getSha256(fileName)
189176
const headersObj = getHeadersObj(sha256, resp.kmsKeyArn)
190177

191-
await sleep(2000) // pause to give time to recognize potential cancellation
192178
throwIfCancelled()
193179
try {
194180
const apiStartTime = Date.now()
@@ -255,7 +241,6 @@ export async function stopJob(jobId: string) {
255241

256242
export async function uploadPayload(payloadFileName: string) {
257243
const sha256 = getSha256(payloadFileName)
258-
await sleep(2000) // pause to give time to recognize potential cancellation
259244
throwIfCancelled()
260245
try {
261246
const apiStartTime = Date.now()
@@ -290,14 +275,25 @@ export async function uploadPayload(payloadFileName: string) {
290275
}
291276
}
292277

293-
function getFilesRecursively(dir: string): string[] {
278+
/**
279+
* Gets all files in dir. We use this method to get the source code, then we run a mvn command to
280+
* copy over dependencies into their own folder, then we use this method again to get those
281+
* dependencies. If isDependenciesFolder is true, then we are getting all the files
282+
* of the dependencies which were copied over by the previously-run mvn command, in which case
283+
* we DO want to include any dependencies that may happen to be named "target", hence the check
284+
* in the first part of the IF statement. The point of excluding folders named target is that
285+
* "target" is also the name of the folder where .class files, large JARs, etc. are stored after
286+
* building, and we do not want these included in the ZIP so we exclude these when calling
287+
* getFilesRecursively on the source code folder.
288+
*/
289+
function getFilesRecursively(dir: string, isDependenciesFolder: boolean): string[] {
294290
const entries = fs.readdirSync(dir, { withFileTypes: true })
295291
const files = entries.flatMap(entry => {
296292
const res = path.resolve(dir, entry.name)
297-
// exclude 'target' directory from ZIP due to issues in backend
293+
// exclude 'target' directory from ZIP (except if zipping dependencies) due to issues in backend
298294
if (entry.isDirectory()) {
299-
if (entry.name !== 'target') {
300-
return getFilesRecursively(res)
295+
if (isDependenciesFolder || entry.name !== 'target') {
296+
return getFilesRecursively(res, isDependenciesFolder)
301297
} else {
302298
return []
303299
}
@@ -324,7 +320,7 @@ function getProjectDependencies(modulePath: string): string[] {
324320
const spawnResult = spawnSync(baseCommand, args, { cwd: modulePath, shell: false, encoding: 'utf-8' })
325321

326322
if (spawnResult.error || spawnResult.status !== 0) {
327-
vscode.window.showErrorMessage(CodeWhispererConstants.dependencyErrorMessage, { modal: true })
323+
vscode.window.showErrorMessage(CodeWhispererConstants.dependencyErrorMessage)
328324
getLogger().error('CodeTransform: Error in running Maven command = ')
329325
// Maven command can still go through and still return an error. Won't be caught in spawnResult.error in this case
330326
if (spawnResult.error) {
@@ -339,13 +335,11 @@ function getProjectDependencies(modulePath: string): string[] {
339335
}
340336

341337
export async function zipCode(modulePath: string) {
342-
await sleep(2000) // pause to give time to recognize potential cancellation
343338
throwIfCancelled()
344339
const zipStartTime = Date.now()
345340
const sourceFolder = modulePath
346-
const sourceFiles = getFilesRecursively(sourceFolder)
341+
const sourceFiles = getFilesRecursively(sourceFolder, false)
347342

348-
await sleep(2000) // pause to give time to recognize potential cancellation
349343
throwIfCancelled()
350344

351345
let dependencyFolderInfo: string[] = []
@@ -359,7 +353,6 @@ export async function zipCode(modulePath: string) {
359353
const dependencyFolderPath = !mavenFailed ? dependencyFolderInfo[0] : ''
360354
const dependencyFolderName = !mavenFailed ? dependencyFolderInfo[1] : ''
361355

362-
await sleep(2000) // pause to give time to recognize potential cancellation
363356
throwIfCancelled()
364357

365358
const zip = new AdmZip()
@@ -371,12 +364,11 @@ export async function zipCode(modulePath: string) {
371364
zip.addLocalFile(file, path.dirname(paddedPath))
372365
}
373366

374-
await sleep(2000) // pause to give time to recognize potential cancellation
375367
throwIfCancelled()
376368

377369
let dependencyFiles: string[] = []
378370
if (!mavenFailed && fs.existsSync(dependencyFolderPath)) {
379-
dependencyFiles = getFilesRecursively(dependencyFolderPath)
371+
dependencyFiles = getFilesRecursively(dependencyFolderPath, true)
380372
}
381373

382374
if (!mavenFailed && dependencyFiles.length > 0) {
@@ -395,7 +387,6 @@ export async function zipCode(modulePath: string) {
395387
}
396388
zip.addFile('manifest.json', Buffer.from(JSON.stringify(zipManifest), 'utf-8'))
397389

398-
await sleep(2000) // pause to give time to recognize potential cancellation
399390
throwIfCancelled()
400391

401392
const tempFilePath = path.join(os.tmpdir(), 'zipped-code.zip')
@@ -605,11 +596,14 @@ export async function pollTransformationJob(jobId: string, validStates: string[]
605596
return status
606597
}
607598

608-
async function checkIfGradle(projectPath: string) {
599+
export async function checkBuildSystem(projectPath: string) {
600+
const mavenBuildFilePath = path.join(projectPath, 'pom.xml')
601+
if (fs.existsSync(mavenBuildFilePath)) {
602+
return BuildSystem.Maven
603+
}
609604
const gradleBuildFilePath = path.join(projectPath, 'build.gradle')
610605
if (fs.existsSync(gradleBuildFilePath)) {
611-
return 'Gradle'
612-
} else {
613-
return 'Unknown'
606+
return BuildSystem.Gradle
614607
}
608+
return BuildSystem.Unknown
615609
}

src/codewhisperer/service/transformationHubViewProvider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export class TransformationHubViewProvider implements vscode.WebviewViewProvider
8585
<th>Module</th>
8686
<th>Status</th>
8787
<th>Duration</th>
88+
<th>Id</th>
8889
</tr>
8990
</thead>
9091
<tbody>
@@ -94,6 +95,7 @@ export class TransformationHubViewProvider implements vscode.WebviewViewProvider
9495
<td>${job.module}</td>
9596
<td>${job.status}</td>
9697
<td>${job.duration}</td>
98+
<td>${job.id}</td>
9799
</tr>`
98100
)}
99101
</tbody>

src/codewhisperer/service/transformationResultsViewProvider.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ export class ProposedTransformationExplorer {
278278
)
279279
} catch (e: any) {
280280
// This allows the customer to retry the download
281+
vscode.window.showErrorMessage('Transform by Q experienced an error when downloading the diff')
281282
vscode.commands.executeCommand('setContext', 'gumby.reviewState', TransformByQReviewStatus.NotStarted)
282283
const errorMessage = 'There was a problem fetching the transformed code.'
283284
getLogger().error('CodeTransform: ExportResultArchive error = ', errorMessage)
@@ -313,8 +314,11 @@ export class ProposedTransformationExplorer {
313314
path.join(pathContainingArchive, ExportResultArchiveStructure.PathToSummary)
314315
)
315316
} catch (e: any) {
316-
deserializeErrorMessage = e?.message || 'Error during deserialization of result archive'
317+
deserializeErrorMessage =
318+
e?.message ||
319+
'Transform by Q experienced an error during the deserialization of the downloaded result archive'
317320
getLogger().error('CodeTransform: ParseDiff error = ', deserializeErrorMessage)
321+
vscode.window.showErrorMessage(deserializeErrorMessage)
318322
} finally {
319323
telemetry.codeTransform_jobArtifactDownloadAndDeserializeTime.emit({
320324
codeTransformSessionId: codeTransformTelemetryState.getSessionId(),
@@ -328,8 +332,7 @@ export class ProposedTransformationExplorer {
328332
}
329333

330334
await vscode.window.showInformationMessage(
331-
'Transformation job completed. You can view the transformation summary along with the proposed changes and accept or reject them in the Proposed Changes panel.',
332-
{ modal: true }
335+
'Transformation job completed. You can view the transformation summary along with the proposed changes and accept or reject them in the Proposed Changes panel.'
333336
)
334337
await vscode.commands.executeCommand('aws.amazonq.transformationHub.summary.reveal')
335338
telemetry.codeTransform_vcsDiffViewerVisible.emit({

0 commit comments

Comments
 (0)